Merge remote-tracking branch 'origin/master' into feat/async-restartable-workers
This commit is contained in:
commit
0de3051821
95
CHANGELOG.md
95
CHANGELOG.md
@ -1,5 +1,98 @@
|
|||||||
# Lotus changelog
|
# 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
|
# 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.
|
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 |
|
| vyzo | 22 | +287/-196 |
|
||||||
| alanshaw | 15 | +761/-146 |
|
| alanshaw | 15 | +761/-146 |
|
||||||
| whyrusleeping | 15 | +736/-52 |
|
| whyrusleeping | 15 | +736/-52 |
|
||||||
| hannahhoward | 14 | +1237/837- |
|
| hannahhoward | 14 | +1237/-837 |
|
||||||
| anton | 6 | +32/-8 |
|
| anton | 6 | +32/-8 |
|
||||||
| travisperson | 5 | +502/-6 |
|
| travisperson | 5 | +502/-6 |
|
||||||
| Frank | 5 | +78/-39 |
|
| Frank | 5 | +78/-39 |
|
||||||
|
@ -484,6 +484,12 @@ type FullNode interface {
|
|||||||
PaychVoucherAdd(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error)
|
PaychVoucherAdd(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error)
|
||||||
PaychVoucherList(context.Context, address.Address) ([]*paych.SignedVoucher, error)
|
PaychVoucherList(context.Context, address.Address) ([]*paych.SignedVoucher, error)
|
||||||
PaychVoucherSubmit(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error)
|
PaychVoucherSubmit(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error)
|
||||||
|
|
||||||
|
// CreateBackup creates node backup onder the specified file name. The
|
||||||
|
// method requires that the lotus daemon is running with the
|
||||||
|
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that
|
||||||
|
// the path specified when calling CreateBackup is within the base path
|
||||||
|
CreateBackup(ctx context.Context, fpath string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileRef struct {
|
type FileRef struct {
|
||||||
@ -530,6 +536,7 @@ type DealInfo struct {
|
|||||||
DealID abi.DealID
|
DealID abi.DealID
|
||||||
|
|
||||||
CreationTime time.Time
|
CreationTime time.Time
|
||||||
|
Verified bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type MsgLookup struct {
|
type MsgLookup struct {
|
||||||
@ -805,14 +812,14 @@ type CirculatingSupply struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MiningBaseInfo struct {
|
type MiningBaseInfo struct {
|
||||||
MinerPower types.BigInt
|
MinerPower types.BigInt
|
||||||
NetworkPower types.BigInt
|
NetworkPower types.BigInt
|
||||||
Sectors []builtin.SectorInfo
|
Sectors []builtin.SectorInfo
|
||||||
WorkerKey address.Address
|
WorkerKey address.Address
|
||||||
SectorSize abi.SectorSize
|
SectorSize abi.SectorSize
|
||||||
PrevBeaconEntry types.BeaconEntry
|
PrevBeaconEntry types.BeaconEntry
|
||||||
BeaconEntries []types.BeaconEntry
|
BeaconEntries []types.BeaconEntry
|
||||||
HasMinPower bool
|
EligibleForMining bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlockTemplate struct {
|
type BlockTemplate struct {
|
||||||
|
@ -102,6 +102,12 @@ type StorageMiner interface {
|
|||||||
PiecesListCidInfos(ctx context.Context) ([]cid.Cid, error)
|
PiecesListCidInfos(ctx context.Context) ([]cid.Cid, error)
|
||||||
PiecesGetPieceInfo(ctx context.Context, pieceCid cid.Cid) (*piecestore.PieceInfo, error)
|
PiecesGetPieceInfo(ctx context.Context, pieceCid cid.Cid) (*piecestore.PieceInfo, error)
|
||||||
PiecesGetCIDInfo(ctx context.Context, payloadCid cid.Cid) (*piecestore.CIDInfo, error)
|
PiecesGetCIDInfo(ctx context.Context, payloadCid cid.Cid) (*piecestore.CIDInfo, error)
|
||||||
|
|
||||||
|
// CreateBackup creates node backup onder the specified file name. The
|
||||||
|
// method requires that the lotus-miner is running with the
|
||||||
|
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that
|
||||||
|
// the path specified when calling CreateBackup is within the base path
|
||||||
|
CreateBackup(ctx context.Context, fpath string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type SealRes struct {
|
type SealRes struct {
|
||||||
|
@ -243,6 +243,8 @@ type FullNodeStruct struct {
|
|||||||
PaychVoucherCreate func(context.Context, address.Address, big.Int, uint64) (*api.VoucherCreateResult, error) `perm:"sign"`
|
PaychVoucherCreate func(context.Context, address.Address, big.Int, uint64) (*api.VoucherCreateResult, error) `perm:"sign"`
|
||||||
PaychVoucherList func(context.Context, address.Address) ([]*paych.SignedVoucher, error) `perm:"write"`
|
PaychVoucherList func(context.Context, address.Address) ([]*paych.SignedVoucher, error) `perm:"write"`
|
||||||
PaychVoucherSubmit func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) `perm:"sign"`
|
PaychVoucherSubmit func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) `perm:"sign"`
|
||||||
|
|
||||||
|
CreateBackup func(ctx context.Context, fpath string) error `perm:"admin"`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,6 +337,8 @@ type StorageMinerStruct struct {
|
|||||||
PiecesListCidInfos func(ctx context.Context) ([]cid.Cid, error) `perm:"read"`
|
PiecesListCidInfos func(ctx context.Context) ([]cid.Cid, error) `perm:"read"`
|
||||||
PiecesGetPieceInfo func(ctx context.Context, pieceCid cid.Cid) (*piecestore.PieceInfo, error) `perm:"read"`
|
PiecesGetPieceInfo func(ctx context.Context, pieceCid cid.Cid) (*piecestore.PieceInfo, error) `perm:"read"`
|
||||||
PiecesGetCIDInfo func(ctx context.Context, payloadCid cid.Cid) (*piecestore.CIDInfo, error) `perm:"read"`
|
PiecesGetCIDInfo func(ctx context.Context, payloadCid cid.Cid) (*piecestore.CIDInfo, error) `perm:"read"`
|
||||||
|
|
||||||
|
CreateBackup func(ctx context.Context, fpath string) error `perm:"admin"`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1052,6 +1056,10 @@ func (c *FullNodeStruct) PaychVoucherSubmit(ctx context.Context, ch address.Addr
|
|||||||
return c.Internal.PaychVoucherSubmit(ctx, ch, sv, secret, proof)
|
return c.Internal.PaychVoucherSubmit(ctx, ch, sv, secret, proof)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) CreateBackup(ctx context.Context, fpath string) error {
|
||||||
|
return c.Internal.CreateBackup(ctx, fpath)
|
||||||
|
}
|
||||||
|
|
||||||
// StorageMinerStruct
|
// StorageMinerStruct
|
||||||
|
|
||||||
func (c *StorageMinerStruct) ActorAddress(ctx context.Context) (address.Address, error) {
|
func (c *StorageMinerStruct) ActorAddress(ctx context.Context) (address.Address, error) {
|
||||||
@ -1336,6 +1344,10 @@ func (c *StorageMinerStruct) PiecesGetCIDInfo(ctx context.Context, payloadCid ci
|
|||||||
return c.Internal.PiecesGetCIDInfo(ctx, payloadCid)
|
return c.Internal.PiecesGetCIDInfo(ctx, payloadCid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *StorageMinerStruct) CreateBackup(ctx context.Context, fpath string) error {
|
||||||
|
return c.Internal.CreateBackup(ctx, fpath)
|
||||||
|
}
|
||||||
|
|
||||||
// WorkerStruct
|
// WorkerStruct
|
||||||
|
|
||||||
func (w *WorkerStruct) Version(ctx context.Context) (build.Version, error) {
|
func (w *WorkerStruct) Version(ctx context.Context) (build.Version, error) {
|
||||||
|
@ -12,15 +12,36 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/node"
|
||||||
"github.com/filecoin-project/lotus/node/impl"
|
"github.com/filecoin-project/lotus/node/impl"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
|
|
||||||
|
for _, height := range []abi.ChainEpoch{
|
||||||
|
1, // before
|
||||||
|
162, // while sealing
|
||||||
|
520, // after upgrade deal
|
||||||
|
5000, // after
|
||||||
|
} {
|
||||||
|
height := height // make linters happy by copying
|
||||||
|
t.Run(fmt.Sprintf("upgrade-%d", height), func(t *testing.T) {
|
||||||
|
testCCUpgrade(t, b, blocktime, height)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, upgradeHeight abi.ChainEpoch) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
n, sn := b(t, 1, OneMiner)
|
n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
||||||
|
Network: build.ActorUpgradeNetworkVersion,
|
||||||
|
Height: upgradeHeight,
|
||||||
|
Migration: stmgr.UpgradeActorsV2,
|
||||||
|
}}))
|
||||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||||
miner := sn[0]
|
miner := sn[0]
|
||||||
|
|
||||||
|
@ -402,9 +402,12 @@ func testRetrieval(t *testing.T, ctx context.Context, client *impl.FullNodeAPI,
|
|||||||
IsCAR: carExport,
|
IsCAR: carExport,
|
||||||
}
|
}
|
||||||
updates, err := client.ClientRetrieveWithEvents(ctx, offers[0].Order(caddr), ref)
|
updates, err := client.ClientRetrieveWithEvents(ctx, offers[0].Order(caddr), ref)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
for update := range updates {
|
for update := range updates {
|
||||||
if update.Err != "" {
|
if update.Err != "" {
|
||||||
t.Fatalf("%v", err)
|
t.Fatalf("retrieval failed: %s", update.Err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,17 +8,21 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/api/apibstore"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
||||||
"github.com/filecoin-project/lotus/chain/events"
|
"github.com/filecoin-project/lotus/chain/events"
|
||||||
"github.com/filecoin-project/lotus/chain/events/state"
|
"github.com/filecoin-project/lotus/chain/events/state"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -133,17 +137,26 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
|||||||
t.Fatal("Unable to settle payment channel")
|
t.Fatal("Unable to settle payment channel")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
creatorStore := adt.WrapStore(ctx, cbor.NewCborStore(apibstore.NewAPIBlockstore(paymentCreator)))
|
||||||
|
|
||||||
// wait for the receiver to submit their vouchers
|
// wait for the receiver to submit their vouchers
|
||||||
ev := events.NewEvents(ctx, paymentCreator)
|
ev := events.NewEvents(ctx, paymentCreator)
|
||||||
preds := state.NewStatePredicates(paymentCreator)
|
preds := state.NewStatePredicates(paymentCreator)
|
||||||
finished := make(chan struct{})
|
finished := make(chan struct{})
|
||||||
err = ev.StateChanged(func(ts *types.TipSet) (done bool, more bool, err error) {
|
err = ev.StateChanged(func(ts *types.TipSet) (done bool, more bool, err error) {
|
||||||
act, err := paymentCreator.StateReadState(ctx, channel, ts.Key())
|
act, err := paymentCreator.StateGetActor(ctx, channel, ts.Key())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, false, err
|
return false, false, err
|
||||||
}
|
}
|
||||||
state := act.State.(paych.State)
|
state, err := paych.Load(creatorStore, act)
|
||||||
if state.ToSend.GreaterThanEqual(abi.NewTokenAmount(6000)) {
|
if err != nil {
|
||||||
|
return false, false, err
|
||||||
|
}
|
||||||
|
toSend, err := state.ToSend()
|
||||||
|
if err != nil {
|
||||||
|
return false, false, err
|
||||||
|
}
|
||||||
|
if toSend.GreaterThanEqual(abi.NewTokenAmount(6000)) {
|
||||||
return true, false, nil
|
return true, false, nil
|
||||||
}
|
}
|
||||||
return false, true, nil
|
return false, true, nil
|
||||||
@ -156,7 +169,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
|||||||
return true, nil
|
return true, nil
|
||||||
}, func(ctx context.Context, ts *types.TipSet) error {
|
}, func(ctx context.Context, ts *types.TipSet) error {
|
||||||
return nil
|
return nil
|
||||||
}, int(build.MessageConfidence)+1, build.SealRandomnessLookbackLimit, func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) {
|
}, int(build.MessageConfidence)+1, build.Finality, func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) {
|
||||||
return preds.OnPaymentChannelActorChanged(channel, preds.OnToSendAmountChanges())(ctx, oldTs.Key(), newTs.Key())
|
return preds.OnPaymentChannelActorChanged(channel, preds.OnToSendAmountChanges())(ctx, oldTs.Key(), newTs.Key())
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -215,7 +228,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wait for the settlement period to pass before collecting
|
// wait for the settlement period to pass before collecting
|
||||||
waitForBlocks(ctx, t, bm, paymentReceiver, receiverAddr, paych.SettleDelay)
|
waitForBlocks(ctx, t, bm, paymentReceiver, receiverAddr, paych0.SettleDelay)
|
||||||
|
|
||||||
creatorPreCollectBalance, err := paymentCreator.WalletBalance(ctx, createrAddr)
|
creatorPreCollectBalance, err := paymentCreator.WalletBalance(ctx, createrAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -271,7 +284,7 @@ func waitForBlocks(ctx context.Context, t *testing.T, bm *BlockMiner, paymentRec
|
|||||||
|
|
||||||
// Add a real block
|
// Add a real block
|
||||||
m, err := paymentReceiver.MpoolPushMessage(ctx, &types.Message{
|
m, err := paymentReceiver.MpoolPushMessage(ctx, &types.Message{
|
||||||
To: builtin.BurntFundsActorAddr,
|
To: builtin0.BurntFundsActorAddr,
|
||||||
From: receiverAddr,
|
From: receiverAddr,
|
||||||
Value: types.NewInt(0),
|
Value: types.NewInt(0),
|
||||||
}, nil)
|
}, nil)
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/miner"
|
"github.com/filecoin-project/lotus/miner"
|
||||||
|
"github.com/filecoin-project/lotus/node"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestNode struct {
|
type TestNode struct {
|
||||||
@ -44,7 +45,7 @@ type StorageMiner struct {
|
|||||||
//
|
//
|
||||||
// storage array defines storage nodes, numbers in the array specify full node
|
// storage array defines storage nodes, numbers in the array specify full node
|
||||||
// index the storage node 'belongs' to
|
// index the storage node 'belongs' to
|
||||||
type APIBuilder func(t *testing.T, nFull int, storage []StorageMiner) ([]TestNode, []TestStorageNode)
|
type APIBuilder func(t *testing.T, nFull int, storage []StorageMiner, opts ...node.Option) ([]TestNode, []TestStorageNode)
|
||||||
type testSuite struct {
|
type testSuite struct {
|
||||||
makeNodes APIBuilder
|
makeNodes APIBuilder
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,11 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/lotus/extern/sector-storage/mock"
|
"github.com/filecoin-project/lotus/extern/sector-storage/mock"
|
||||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||||
|
"github.com/filecoin-project/lotus/node"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
bminer "github.com/filecoin-project/lotus/miner"
|
bminer "github.com/filecoin-project/lotus/miner"
|
||||||
"github.com/filecoin-project/lotus/node/impl"
|
"github.com/filecoin-project/lotus/node/impl"
|
||||||
@ -114,8 +116,29 @@ func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
|
func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
|
||||||
ctx := context.Background()
|
for _, height := range []abi.ChainEpoch{
|
||||||
n, sn := b(t, 1, OneMiner)
|
1, // before
|
||||||
|
162, // while sealing
|
||||||
|
5000, // while proving
|
||||||
|
} {
|
||||||
|
height := height // copy to satisfy lints
|
||||||
|
t.Run(fmt.Sprintf("upgrade-%d", height), func(t *testing.T) {
|
||||||
|
testWindowPostUpgrade(t, b, blocktime, nSectors, height)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
func testWindowPostUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int,
|
||||||
|
upgradeHeight abi.ChainEpoch) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
||||||
|
Network: build.ActorUpgradeNetworkVersion,
|
||||||
|
Height: upgradeHeight,
|
||||||
|
Migration: stmgr.UpgradeActorsV2,
|
||||||
|
}}))
|
||||||
|
|
||||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||||
miner := sn[0]
|
miner := sn[0]
|
||||||
|
|
||||||
@ -129,17 +152,24 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
|||||||
}
|
}
|
||||||
build.Clock.Sleep(time.Second)
|
build.Clock.Sleep(time.Second)
|
||||||
|
|
||||||
mine := true
|
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
defer close(done)
|
defer close(done)
|
||||||
for mine {
|
for ctx.Err() == nil {
|
||||||
build.Clock.Sleep(blocktime)
|
build.Clock.Sleep(blocktime)
|
||||||
if err := sn[0].MineOne(ctx, MineNext); err != nil {
|
if err := sn[0].MineOne(ctx, MineNext); err != nil {
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
// context was canceled, ignore the error.
|
||||||
|
return
|
||||||
|
}
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
defer func() {
|
||||||
|
cancel()
|
||||||
|
<-done
|
||||||
|
}()
|
||||||
|
|
||||||
pledgeSectors(t, ctx, miner, nSectors, 0, nil)
|
pledgeSectors(t, ctx, miner, nSectors, 0, nil)
|
||||||
|
|
||||||
@ -159,7 +189,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
|||||||
head, err := client.ChainHead(ctx)
|
head, err := client.ChainHead(ctx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if head.Height() > di.PeriodStart+(di.WPoStProvingPeriod)+2 {
|
if head.Height() > di.PeriodStart+di.WPoStProvingPeriod+2 {
|
||||||
fmt.Printf("Now head.Height = %d\n", head.Height())
|
fmt.Printf("Now head.Height = %d\n", head.Height())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -289,12 +319,11 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
|||||||
pledgeSectors(t, ctx, miner, 1, nSectors, nil)
|
pledgeSectors(t, ctx, miner, 1, nSectors, nil)
|
||||||
|
|
||||||
{
|
{
|
||||||
// wait a bit more
|
// Wait until proven.
|
||||||
|
di, err = client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK)
|
||||||
head, err := client.ChainHead(ctx)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
waitUntil := head.Height() + 10
|
waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2
|
||||||
fmt.Printf("End for head.Height > %d\n", waitUntil)
|
fmt.Printf("End for head.Height > %d\n", waitUntil)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -315,7 +344,4 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
|||||||
|
|
||||||
sectors = p.MinerPower.RawBytePower.Uint64() / uint64(ssz)
|
sectors = p.MinerPower.RawBytePower.Uint64() / uint64(ssz)
|
||||||
require.Equal(t, nSectors+GenesisPreseals-2+1, int(sectors)) // -2 not recovered sectors + 1 just pledged
|
require.Equal(t, nSectors+GenesisPreseals-2+1, int(sectors)) // -2 not recovered sectors + 1 just pledged
|
||||||
|
|
||||||
mine = false
|
|
||||||
<-done
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
@ -13,7 +16,10 @@ const BreezeGasTampingDuration = 0
|
|||||||
|
|
||||||
const UpgradeSmokeHeight = -1
|
const UpgradeSmokeHeight = -1
|
||||||
const UpgradeIgnitionHeight = -2
|
const UpgradeIgnitionHeight = -2
|
||||||
const UpgradeLiftoffHeight = -3
|
const UpgradeRefuelHeight = -3
|
||||||
|
|
||||||
|
var UpgradeActorsV2Height = abi.ChainEpoch(10)
|
||||||
|
var UpgradeLiftoffHeight = abi.ChainEpoch(-4)
|
||||||
|
|
||||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||||
0: DrandMainnet,
|
0: DrandMainnet,
|
||||||
@ -24,6 +30,11 @@ func init() {
|
|||||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||||
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||||
|
|
||||||
|
if os.Getenv("LOTUS_DISABLE_V2_ACTOR_MIGRATION") == "1" {
|
||||||
|
UpgradeActorsV2Height = math.MaxInt64
|
||||||
|
UpgradeLiftoffHeight = 11
|
||||||
|
}
|
||||||
|
|
||||||
BuildType |= Build2k
|
BuildType |= Build2k
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ func DhtProtocolName(netName dtypes.NetworkName) protocol.ID {
|
|||||||
|
|
||||||
func UseNewestNetwork() bool {
|
func UseNewestNetwork() bool {
|
||||||
// TODO: Put these in a container we can iterate over
|
// TODO: Put these in a container we can iterate over
|
||||||
if UpgradeBreezeHeight <= 0 && UpgradeSmokeHeight <= 0 {
|
if UpgradeBreezeHeight <= 0 && UpgradeSmokeHeight <= 0 && UpgradeActorsV2Height <= 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -7,12 +7,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// /////
|
// /////
|
||||||
@ -25,7 +25,7 @@ const UnixfsLinksPerLevel = 1024
|
|||||||
// Consensus / Network
|
// Consensus / Network
|
||||||
|
|
||||||
const AllowableClockDriftSecs = uint64(1)
|
const AllowableClockDriftSecs = uint64(1)
|
||||||
const NewestNetworkVersion = network.Version3
|
const NewestNetworkVersion = network.Version4
|
||||||
const ActorUpgradeNetworkVersion = network.Version4
|
const ActorUpgradeNetworkVersion = network.Version4
|
||||||
|
|
||||||
// Epochs
|
// Epochs
|
||||||
@ -35,7 +35,7 @@ const ForkLengthThreshold = Finality
|
|||||||
var BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch)
|
var BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch)
|
||||||
|
|
||||||
// Epochs
|
// Epochs
|
||||||
const Finality = miner0.ChainFinality
|
const Finality = policy.ChainFinality
|
||||||
const MessageConfidence = uint64(5)
|
const MessageConfidence = uint64(5)
|
||||||
|
|
||||||
// constants for Weight calculation
|
// constants for Weight calculation
|
||||||
@ -47,13 +47,8 @@ const WRatioDen = uint64(2)
|
|||||||
// Proofs
|
// Proofs
|
||||||
|
|
||||||
// Epochs
|
// Epochs
|
||||||
const SealRandomnessLookback = Finality
|
// TODO: unused
|
||||||
|
const SealRandomnessLookback = policy.SealRandomnessLookback
|
||||||
// Epochs
|
|
||||||
const SealRandomnessLookbackLimit = SealRandomnessLookback + 2000 // TODO: Get from spec specs-actors
|
|
||||||
|
|
||||||
// Maximum lookback that randomness can be sourced from for a seal proof submission
|
|
||||||
const MaxSealLookback = SealRandomnessLookbackLimit + 2000 // TODO: Get from specs-actors
|
|
||||||
|
|
||||||
// /////
|
// /////
|
||||||
// Mining
|
// Mining
|
||||||
@ -61,8 +56,6 @@ const MaxSealLookback = SealRandomnessLookbackLimit + 2000 // TODO: Get from spe
|
|||||||
// Epochs
|
// Epochs
|
||||||
const TicketRandomnessLookback = abi.ChainEpoch(1)
|
const TicketRandomnessLookback = abi.ChainEpoch(1)
|
||||||
|
|
||||||
const WinningPoStSectorSetLookback = abi.ChainEpoch(10)
|
|
||||||
|
|
||||||
// /////
|
// /////
|
||||||
// Address
|
// Address
|
||||||
|
|
||||||
@ -77,8 +70,10 @@ const FilBase = uint64(2_000_000_000)
|
|||||||
const FilAllocStorageMining = uint64(1_100_000_000)
|
const FilAllocStorageMining = uint64(1_100_000_000)
|
||||||
|
|
||||||
const FilecoinPrecision = uint64(1_000_000_000_000_000_000)
|
const FilecoinPrecision = uint64(1_000_000_000_000_000_000)
|
||||||
|
const FilReserved = uint64(300_000_000)
|
||||||
|
|
||||||
var InitialRewardBalance *big.Int
|
var InitialRewardBalance *big.Int
|
||||||
|
var InitialFilReserved *big.Int
|
||||||
|
|
||||||
// TODO: Move other important consts here
|
// TODO: Move other important consts here
|
||||||
|
|
||||||
@ -86,6 +81,9 @@ func init() {
|
|||||||
InitialRewardBalance = big.NewInt(int64(FilAllocStorageMining))
|
InitialRewardBalance = big.NewInt(int64(FilAllocStorageMining))
|
||||||
InitialRewardBalance = InitialRewardBalance.Mul(InitialRewardBalance, big.NewInt(int64(FilecoinPrecision)))
|
InitialRewardBalance = InitialRewardBalance.Mul(InitialRewardBalance, big.NewInt(int64(FilecoinPrecision)))
|
||||||
|
|
||||||
|
InitialFilReserved = big.NewInt(int64(FilReserved))
|
||||||
|
InitialFilReserved = InitialFilReserved.Mul(InitialFilReserved, big.NewInt(int64(FilecoinPrecision)))
|
||||||
|
|
||||||
if os.Getenv("LOTUS_ADDRESS_TYPE") == AddressMainnetEnvVar {
|
if os.Getenv("LOTUS_ADDRESS_TYPE") == AddressMainnetEnvVar {
|
||||||
SetAddressNetwork(address.Mainnet)
|
SetAddressNetwork(address.Mainnet)
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,8 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -32,7 +33,7 @@ var (
|
|||||||
|
|
||||||
AllowableClockDriftSecs = uint64(1)
|
AllowableClockDriftSecs = uint64(1)
|
||||||
|
|
||||||
Finality = miner0.ChainFinality
|
Finality = policy.ChainFinality
|
||||||
ForkLengthThreshold = Finality
|
ForkLengthThreshold = Finality
|
||||||
|
|
||||||
SlashablePowerDelay = 20
|
SlashablePowerDelay = 20
|
||||||
@ -47,15 +48,13 @@ var (
|
|||||||
BlsSignatureCacheSize = 40000
|
BlsSignatureCacheSize = 40000
|
||||||
VerifSigCacheSize = 32000
|
VerifSigCacheSize = 32000
|
||||||
|
|
||||||
SealRandomnessLookback = Finality
|
SealRandomnessLookback = policy.SealRandomnessLookback
|
||||||
SealRandomnessLookbackLimit = SealRandomnessLookback + 2000
|
|
||||||
MaxSealLookback = SealRandomnessLookbackLimit + 2000
|
|
||||||
|
|
||||||
TicketRandomnessLookback = abi.ChainEpoch(1)
|
TicketRandomnessLookback = abi.ChainEpoch(1)
|
||||||
WinningPoStSectorSetLookback = abi.ChainEpoch(10)
|
|
||||||
|
|
||||||
FilBase uint64 = 2_000_000_000
|
FilBase uint64 = 2_000_000_000
|
||||||
FilAllocStorageMining uint64 = 1_400_000_000
|
FilAllocStorageMining uint64 = 1_400_000_000
|
||||||
|
FilReserved uint64 = 300_000_000
|
||||||
|
|
||||||
FilecoinPrecision uint64 = 1_000_000_000_000_000_000
|
FilecoinPrecision uint64 = 1_000_000_000_000_000_000
|
||||||
|
|
||||||
@ -64,6 +63,13 @@ var (
|
|||||||
v = v.Mul(v, big.NewInt(int64(FilecoinPrecision)))
|
v = v.Mul(v, big.NewInt(int64(FilecoinPrecision)))
|
||||||
return v
|
return v
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
InitialFilReserved = func() *big.Int {
|
||||||
|
v := big.NewInt(int64(FilReserved))
|
||||||
|
v = v.Mul(v, big.NewInt(int64(FilecoinPrecision)))
|
||||||
|
return v
|
||||||
|
}()
|
||||||
|
|
||||||
// Actor consts
|
// Actor consts
|
||||||
// TODO: Pull from actors when its made not private
|
// TODO: Pull from actors when its made not private
|
||||||
MinDealDuration = abi.ChainEpoch(180 * builtin.EpochsInDay)
|
MinDealDuration = abi.ChainEpoch(180 * builtin.EpochsInDay)
|
||||||
@ -76,14 +82,16 @@ var (
|
|||||||
|
|
||||||
UpgradeSmokeHeight abi.ChainEpoch = -1
|
UpgradeSmokeHeight abi.ChainEpoch = -1
|
||||||
UpgradeIgnitionHeight abi.ChainEpoch = -2
|
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{
|
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||||
0: DrandMainnet,
|
0: DrandMainnet,
|
||||||
}
|
}
|
||||||
|
|
||||||
NewestNetworkVersion = network.Version2
|
NewestNetworkVersion = network.Version4
|
||||||
ActorUpgradeNetworkVersion = network.Version3
|
ActorUpgradeNetworkVersion = network.Version4
|
||||||
|
|
||||||
Devnet = true
|
Devnet = true
|
||||||
)
|
)
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
|
|
||||||
@ -22,6 +26,9 @@ const BreezeGasTampingDuration = 120
|
|||||||
const UpgradeSmokeHeight = 51000
|
const UpgradeSmokeHeight = 51000
|
||||||
|
|
||||||
const UpgradeIgnitionHeight = 94000
|
const UpgradeIgnitionHeight = 94000
|
||||||
|
const UpgradeRefuelHeight = 130800
|
||||||
|
|
||||||
|
var UpgradeActorsV2Height = abi.ChainEpoch(138720)
|
||||||
|
|
||||||
// This signals our tentative epoch for mainnet launch. Can make it later, but not earlier.
|
// This signals our tentative epoch for mainnet launch. Can make it later, but not earlier.
|
||||||
// Miners, clients, developers, custodians all need time to prepare.
|
// Miners, clients, developers, custodians all need time to prepare.
|
||||||
@ -34,6 +41,15 @@ func init() {
|
|||||||
abi.RegisteredSealProof_StackedDrg32GiBV1,
|
abi.RegisteredSealProof_StackedDrg32GiBV1,
|
||||||
abi.RegisteredSealProof_StackedDrg64GiBV1,
|
abi.RegisteredSealProof_StackedDrg64GiBV1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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
|
Devnet = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ func buildType() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BuildVersion is the local build version, set by build system
|
// BuildVersion is the local build version, set by build system
|
||||||
const BuildVersion = "0.8.1"
|
const BuildVersion = "0.9.0"
|
||||||
|
|
||||||
func UserVersion() string {
|
func UserVersion() string {
|
||||||
return BuildVersion + buildType() + CurrentCommit
|
return BuildVersion + buildType() + CurrentCommit
|
||||||
|
@ -7,8 +7,11 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/cbor"
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
|
||||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Map interface {
|
type Map interface {
|
||||||
@ -21,18 +24,22 @@ type Map interface {
|
|||||||
ForEach(v cbor.Unmarshaler, fn func(key string) error) error
|
ForEach(v cbor.Unmarshaler, fn func(key string) error) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func AsMap(store Store, root cid.Cid, version builtin.Version) (Map, error) {
|
func AsMap(store Store, root cid.Cid, version actors.Version) (Map, error) {
|
||||||
switch version {
|
switch version {
|
||||||
case builtin.Version0:
|
case actors.Version0:
|
||||||
return adt0.AsMap(store, root)
|
return adt0.AsMap(store, root)
|
||||||
|
case actors.Version2:
|
||||||
|
return adt2.AsMap(store, root)
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("unknown network version: %d", version)
|
return nil, xerrors.Errorf("unknown network version: %d", version)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMap(store Store, version builtin.Version) (Map, error) {
|
func NewMap(store Store, version actors.Version) (Map, error) {
|
||||||
switch version {
|
switch version {
|
||||||
case builtin.Version0:
|
case actors.Version0:
|
||||||
return adt0.MakeEmptyMap(store), nil
|
return adt0.MakeEmptyMap(store), nil
|
||||||
|
case actors.Version2:
|
||||||
|
return adt2.MakeEmptyMap(store), nil
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("unknown network version: %d", version)
|
return nil, xerrors.Errorf("unknown network version: %d", version)
|
||||||
}
|
}
|
||||||
@ -49,17 +56,21 @@ type Array interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func AsArray(store Store, root cid.Cid, version network.Version) (Array, error) {
|
func AsArray(store Store, root cid.Cid, version network.Version) (Array, error) {
|
||||||
switch builtin.VersionForNetwork(version) {
|
switch actors.VersionForNetwork(version) {
|
||||||
case builtin.Version0:
|
case actors.Version0:
|
||||||
return adt0.AsArray(store, root)
|
return adt0.AsArray(store, root)
|
||||||
|
case actors.Version2:
|
||||||
|
return adt2.AsArray(store, root)
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("unknown network version: %d", version)
|
return nil, xerrors.Errorf("unknown network version: %d", version)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewArray(store Store, version builtin.Version) (Array, error) {
|
func NewArray(store Store, version actors.Version) (Array, error) {
|
||||||
switch version {
|
switch version {
|
||||||
case builtin.Version0:
|
case actors.Version0:
|
||||||
return adt0.MakeEmptyArray(store), nil
|
return adt0.MakeEmptyArray(store), nil
|
||||||
|
case actors.Version2:
|
||||||
|
return adt2.MakeEmptyArray(store), nil
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("unknown network version: %d", version)
|
return nil, xerrors.Errorf("unknown network version: %d", version)
|
||||||
}
|
}
|
||||||
|
@ -5,21 +5,31 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/cbor"
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
|
||||||
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
builtin.RegisterActorState(builtin0.AccountActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load0(store, root)
|
||||||
|
})
|
||||||
|
builtin.RegisterActorState(builtin2.AccountActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load2(store, root)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func Load(store adt.Store, act *types.Actor) (State, error) {
|
func Load(store adt.Store, act *types.Actor) (State, error) {
|
||||||
switch act.Code {
|
switch act.Code {
|
||||||
case builtin0.AccountActorCodeID:
|
case builtin0.AccountActorCodeID:
|
||||||
out := state0{store: store}
|
return load0(store, act.Head)
|
||||||
err := store.Get(store.Context(), act.Head, &out)
|
case builtin2.AccountActorCodeID:
|
||||||
if err != nil {
|
return load2(store, act.Head)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &out, nil
|
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,26 @@ package account
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
|
||||||
|
account0 "github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ State = (*state0)(nil)
|
var _ State = (*state0)(nil)
|
||||||
|
|
||||||
|
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state0{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
type state0 struct {
|
type state0 struct {
|
||||||
account.State
|
account0.State
|
||||||
store adt.Store
|
store adt.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
30
chain/actors/builtin/account/v2.go
Normal file
30
chain/actors/builtin/account/v2.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package account
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
|
||||||
|
account2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/account"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ State = (*state2)(nil)
|
||||||
|
|
||||||
|
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state2{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type state2 struct {
|
||||||
|
account2.State
|
||||||
|
store adt.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) PubkeyAddress() (address.Address, error) {
|
||||||
|
return s.Address, nil
|
||||||
|
}
|
@ -1,32 +1,28 @@
|
|||||||
package builtin
|
package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
|
||||||
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||||
|
|
||||||
smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing"
|
smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Version int
|
var SystemActorAddr = builtin0.SystemActorAddr
|
||||||
|
var BurntFundsActorAddr = builtin0.BurntFundsActorAddr
|
||||||
const (
|
var ReserveAddress = makeAddress("t090")
|
||||||
Version0 = iota
|
var RootVerifierAddress = makeAddress("t080")
|
||||||
)
|
|
||||||
|
|
||||||
// Converts a network version into a specs-actors version.
|
|
||||||
func VersionForNetwork(version network.Version) Version {
|
|
||||||
switch version {
|
|
||||||
case network.Version0, network.Version1, network.Version2, network.Version3:
|
|
||||||
return Version0
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("unsupported network version %d", version))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Why does actors have 2 different versions of this?
|
// TODO: Why does actors have 2 different versions of this?
|
||||||
type SectorInfo = proof0.SectorInfo
|
type SectorInfo = proof0.SectorInfo
|
||||||
@ -41,3 +37,64 @@ func FromV0FilterEstimate(v0 smoothing0.FilterEstimate) FilterEstimate {
|
|||||||
func QAPowerForWeight(size abi.SectorSize, duration abi.ChainEpoch, dealWeight, verifiedWeight abi.DealWeight) abi.StoragePower {
|
func QAPowerForWeight(size abi.SectorSize, duration abi.ChainEpoch, dealWeight, verifiedWeight abi.DealWeight) abi.StoragePower {
|
||||||
return miner0.QAPowerForWeight(size, duration, dealWeight, verifiedWeight)
|
return miner0.QAPowerForWeight(size, duration, dealWeight, verifiedWeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FromV2FilterEstimate(v1 smoothing2.FilterEstimate) FilterEstimate {
|
||||||
|
return (FilterEstimate)(v1)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ActorStateLoader func(store adt.Store, root cid.Cid) (cbor.Marshaler, error)
|
||||||
|
|
||||||
|
var ActorStateLoaders = make(map[cid.Cid]ActorStateLoader)
|
||||||
|
|
||||||
|
func RegisterActorState(code cid.Cid, loader ActorStateLoader) {
|
||||||
|
ActorStateLoaders[code] = loader
|
||||||
|
}
|
||||||
|
|
||||||
|
func Load(store adt.Store, act *types.Actor) (cbor.Marshaler, error) {
|
||||||
|
loader, found := ActorStateLoaders[act.Code]
|
||||||
|
if !found {
|
||||||
|
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||||
|
}
|
||||||
|
return loader(store, act.Head)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ActorNameByCode(c cid.Cid) string {
|
||||||
|
switch {
|
||||||
|
case builtin0.IsBuiltinActor(c):
|
||||||
|
return builtin0.ActorNameByCode(c)
|
||||||
|
case builtin2.IsBuiltinActor(c):
|
||||||
|
return builtin2.ActorNameByCode(c)
|
||||||
|
default:
|
||||||
|
return "<unknown>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsBuiltinActor(c cid.Cid) bool {
|
||||||
|
return builtin0.IsBuiltinActor(c) || builtin2.IsBuiltinActor(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsAccountActor(c cid.Cid) bool {
|
||||||
|
return c == builtin0.AccountActorCodeID || c == builtin2.AccountActorCodeID
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsStorageMinerActor(c cid.Cid) bool {
|
||||||
|
return c == builtin0.StorageMinerActorCodeID || c == builtin2.StorageMinerActorCodeID
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsMultisigActor(c cid.Cid) bool {
|
||||||
|
return c == builtin0.MultisigActorCodeID || c == builtin2.MultisigActorCodeID
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsPaymentChannelActor(c cid.Cid) bool {
|
||||||
|
return c == builtin0.PaymentChannelActorCodeID || c == builtin2.PaymentChannelActorCodeID
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeAddress(addr string) address.Address {
|
||||||
|
ret, err := address.NewFromString(addr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
@ -6,24 +6,34 @@ import (
|
|||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/cbor"
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
|
|
||||||
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
builtin.RegisterActorState(builtin0.InitActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load0(store, root)
|
||||||
|
})
|
||||||
|
builtin.RegisterActorState(builtin2.InitActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load2(store, root)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
var Address = builtin0.InitActorAddr
|
var Address = builtin0.InitActorAddr
|
||||||
|
|
||||||
func Load(store adt.Store, act *types.Actor) (State, error) {
|
func Load(store adt.Store, act *types.Actor) (State, error) {
|
||||||
switch act.Code {
|
switch act.Code {
|
||||||
case builtin0.InitActorCodeID:
|
case builtin0.InitActorCodeID:
|
||||||
out := state0{store: store}
|
return load0(store, act.Head)
|
||||||
err := store.Get(store.Context(), act.Head, &out)
|
case builtin2.InitActorCodeID:
|
||||||
if err != nil {
|
return load2(store, act.Head)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &out, nil
|
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||||
}
|
}
|
||||||
@ -41,4 +51,7 @@ type State interface {
|
|||||||
// It should not be used in production code, as init actor entries are
|
// It should not be used in production code, as init actor entries are
|
||||||
// immutable.
|
// immutable.
|
||||||
Remove(addrs ...address.Address) error
|
Remove(addrs ...address.Address) error
|
||||||
|
|
||||||
|
// Sets the network's name. This should only be used on upgrade/fork.
|
||||||
|
SetNetworkName(name string) error
|
||||||
}
|
}
|
||||||
|
@ -3,21 +3,30 @@ package init
|
|||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
|
|
||||||
|
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ State = (*state0)(nil)
|
var _ State = (*state0)(nil)
|
||||||
|
|
||||||
|
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state0{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
type state0 struct {
|
type state0 struct {
|
||||||
init_.State
|
init0.State
|
||||||
store adt.Store
|
store adt.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,6 +57,11 @@ func (s *state0) NetworkName() (dtypes.NetworkName, error) {
|
|||||||
return dtypes.NetworkName(s.State.NetworkName), nil
|
return dtypes.NetworkName(s.State.NetworkName), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *state0) SetNetworkName(name string) error {
|
||||||
|
s.State.NetworkName = name
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *state0) Remove(addrs ...address.Address) (err error) {
|
func (s *state0) Remove(addrs ...address.Address) (err error) {
|
||||||
m, err := adt0.AsMap(s.store, s.State.AddressMap)
|
m, err := adt0.AsMap(s.store, s.State.AddressMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
81
chain/actors/builtin/init/v2.go
Normal file
81
chain/actors/builtin/init/v2.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package init
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
|
|
||||||
|
init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init"
|
||||||
|
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ State = (*state2)(nil)
|
||||||
|
|
||||||
|
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state2{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type state2 struct {
|
||||||
|
init2.State
|
||||||
|
store adt.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) ResolveAddress(address address.Address) (address.Address, bool, error) {
|
||||||
|
return s.State.ResolveAddress(s.store, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) MapAddressToNewID(address address.Address) (address.Address, error) {
|
||||||
|
return s.State.MapAddressToNewID(s.store, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) ForEachActor(cb func(id abi.ActorID, address address.Address) error) error {
|
||||||
|
addrs, err := adt2.AsMap(s.store, s.State.AddressMap)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var actorID cbg.CborInt
|
||||||
|
return addrs.ForEach(&actorID, func(key string) error {
|
||||||
|
addr, err := address.NewFromBytes([]byte(key))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return cb(abi.ActorID(actorID), addr)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) NetworkName() (dtypes.NetworkName, error) {
|
||||||
|
return dtypes.NetworkName(s.State.NetworkName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) SetNetworkName(name string) error {
|
||||||
|
s.State.NetworkName = name
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) Remove(addrs ...address.Address) (err error) {
|
||||||
|
m, err := adt2.AsMap(s.store, s.State.AddressMap)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if err = m.Delete(abi.AddrKey(addr)); err != nil {
|
||||||
|
return xerrors.Errorf("failed to delete entry for address: %s; err: %w", addr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
amr, err := m.Root()
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to get address map root: %w", err)
|
||||||
|
}
|
||||||
|
s.State.AddressMap = amr
|
||||||
|
return nil
|
||||||
|
}
|
@ -6,26 +6,35 @@ import (
|
|||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/cbor"
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
|
||||||
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
builtin.RegisterActorState(builtin0.StorageMarketActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load0(store, root)
|
||||||
|
})
|
||||||
|
builtin.RegisterActorState(builtin2.StorageMarketActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load2(store, root)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
var Address = builtin0.StorageMarketActorAddr
|
var Address = builtin0.StorageMarketActorAddr
|
||||||
|
|
||||||
func Load(store adt.Store, act *types.Actor) (st State, err error) {
|
func Load(store adt.Store, act *types.Actor) (st State, err error) {
|
||||||
switch act.Code {
|
switch act.Code {
|
||||||
case builtin0.StorageMarketActorCodeID:
|
case builtin0.StorageMarketActorCodeID:
|
||||||
out := state0{store: store}
|
return load0(store, act.Head)
|
||||||
err := store.Get(store.Context(), act.Head, &out)
|
case builtin2.StorageMarketActorCodeID:
|
||||||
if err != nil {
|
return load2(store, act.Head)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &out, nil
|
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||||
}
|
}
|
||||||
|
@ -5,17 +5,29 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
|
||||||
|
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ State = (*state0)(nil)
|
var _ State = (*state0)(nil)
|
||||||
|
|
||||||
|
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state0{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
type state0 struct {
|
type state0 struct {
|
||||||
market.State
|
market0.State
|
||||||
store adt.Store
|
store adt.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +102,7 @@ func (s *state0) LockedTable() (BalanceTable, error) {
|
|||||||
func (s *state0) VerifyDealsForActivation(
|
func (s *state0) VerifyDealsForActivation(
|
||||||
minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch,
|
minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch,
|
||||||
) (weight, verifiedWeight abi.DealWeight, err error) {
|
) (weight, verifiedWeight abi.DealWeight, err error) {
|
||||||
return market.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch)
|
return market0.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch)
|
||||||
}
|
}
|
||||||
|
|
||||||
type balanceTable0 struct {
|
type balanceTable0 struct {
|
||||||
@ -114,7 +126,7 @@ type dealStates0 struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *dealStates0) Get(dealID abi.DealID) (*DealState, bool, error) {
|
func (s *dealStates0) Get(dealID abi.DealID) (*DealState, bool, error) {
|
||||||
var deal0 market.DealState
|
var deal0 market0.DealState
|
||||||
found, err := s.Array.Get(uint64(dealID), &deal0)
|
found, err := s.Array.Get(uint64(dealID), &deal0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
@ -127,14 +139,14 @@ func (s *dealStates0) Get(dealID abi.DealID) (*DealState, bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *dealStates0) ForEach(cb func(dealID abi.DealID, ds DealState) error) error {
|
func (s *dealStates0) ForEach(cb func(dealID abi.DealID, ds DealState) error) error {
|
||||||
var ds0 market.DealState
|
var ds0 market0.DealState
|
||||||
return s.Array.ForEach(&ds0, func(idx int64) error {
|
return s.Array.ForEach(&ds0, func(idx int64) error {
|
||||||
return cb(abi.DealID(idx), fromV0DealState(ds0))
|
return cb(abi.DealID(idx), fromV0DealState(ds0))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *dealStates0) decode(val *cbg.Deferred) (*DealState, error) {
|
func (s *dealStates0) decode(val *cbg.Deferred) (*DealState, error) {
|
||||||
var ds0 market.DealState
|
var ds0 market0.DealState
|
||||||
if err := ds0.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil {
|
if err := ds0.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -146,7 +158,7 @@ func (s *dealStates0) array() adt.Array {
|
|||||||
return s.Array
|
return s.Array
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromV0DealState(v0 market.DealState) DealState {
|
func fromV0DealState(v0 market0.DealState) DealState {
|
||||||
return (DealState)(v0)
|
return (DealState)(v0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +167,7 @@ type dealProposals0 struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *dealProposals0) Get(dealID abi.DealID) (*DealProposal, bool, error) {
|
func (s *dealProposals0) Get(dealID abi.DealID) (*DealProposal, bool, error) {
|
||||||
var proposal0 market.DealProposal
|
var proposal0 market0.DealProposal
|
||||||
found, err := s.Array.Get(uint64(dealID), &proposal0)
|
found, err := s.Array.Get(uint64(dealID), &proposal0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
@ -168,14 +180,14 @@ func (s *dealProposals0) Get(dealID abi.DealID) (*DealProposal, bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *dealProposals0) ForEach(cb func(dealID abi.DealID, dp DealProposal) error) error {
|
func (s *dealProposals0) ForEach(cb func(dealID abi.DealID, dp DealProposal) error) error {
|
||||||
var dp0 market.DealProposal
|
var dp0 market0.DealProposal
|
||||||
return s.Array.ForEach(&dp0, func(idx int64) error {
|
return s.Array.ForEach(&dp0, func(idx int64) error {
|
||||||
return cb(abi.DealID(idx), fromV0DealProposal(dp0))
|
return cb(abi.DealID(idx), fromV0DealProposal(dp0))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *dealProposals0) decode(val *cbg.Deferred) (*DealProposal, error) {
|
func (s *dealProposals0) decode(val *cbg.Deferred) (*DealProposal, error) {
|
||||||
var dp0 market.DealProposal
|
var dp0 market0.DealProposal
|
||||||
if err := dp0.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil {
|
if err := dp0.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -187,6 +199,6 @@ func (s *dealProposals0) array() adt.Array {
|
|||||||
return s.Array
|
return s.Array
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromV0DealProposal(v0 market.DealProposal) DealProposal {
|
func fromV0DealProposal(v0 market0.DealProposal) DealProposal {
|
||||||
return (DealProposal)(v0)
|
return (DealProposal)(v0)
|
||||||
}
|
}
|
||||||
|
205
chain/actors/builtin/market/v2.go
Normal file
205
chain/actors/builtin/market/v2.go
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
package market
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
|
||||||
|
market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market"
|
||||||
|
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ State = (*state2)(nil)
|
||||||
|
|
||||||
|
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state2{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type state2 struct {
|
||||||
|
market2.State
|
||||||
|
store adt.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) TotalLocked() (abi.TokenAmount, error) {
|
||||||
|
fml := types.BigAdd(s.TotalClientLockedCollateral, s.TotalProviderLockedCollateral)
|
||||||
|
fml = types.BigAdd(fml, s.TotalClientStorageFee)
|
||||||
|
return fml, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) BalancesChanged(otherState State) (bool, error) {
|
||||||
|
otherState2, ok := otherState.(*state2)
|
||||||
|
if !ok {
|
||||||
|
// there's no way to compare different versions of the state, so let's
|
||||||
|
// just say that means the state of balances has changed
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return !s.State.EscrowTable.Equals(otherState2.State.EscrowTable) || !s.State.LockedTable.Equals(otherState2.State.LockedTable), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) StatesChanged(otherState State) (bool, error) {
|
||||||
|
otherState2, ok := otherState.(*state2)
|
||||||
|
if !ok {
|
||||||
|
// there's no way to compare different versions of the state, so let's
|
||||||
|
// just say that means the state of balances has changed
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return !s.State.States.Equals(otherState2.State.States), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) States() (DealStates, error) {
|
||||||
|
stateArray, err := adt2.AsArray(s.store, s.State.States)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &dealStates2{stateArray}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) ProposalsChanged(otherState State) (bool, error) {
|
||||||
|
otherState2, ok := otherState.(*state2)
|
||||||
|
if !ok {
|
||||||
|
// there's no way to compare different versions of the state, so let's
|
||||||
|
// just say that means the state of balances has changed
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return !s.State.Proposals.Equals(otherState2.State.Proposals), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) Proposals() (DealProposals, error) {
|
||||||
|
proposalArray, err := adt2.AsArray(s.store, s.State.Proposals)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &dealProposals2{proposalArray}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) EscrowTable() (BalanceTable, error) {
|
||||||
|
bt, err := adt2.AsBalanceTable(s.store, s.State.EscrowTable)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &balanceTable2{bt}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) LockedTable() (BalanceTable, error) {
|
||||||
|
bt, err := adt2.AsBalanceTable(s.store, s.State.LockedTable)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &balanceTable2{bt}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) VerifyDealsForActivation(
|
||||||
|
minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch,
|
||||||
|
) (weight, verifiedWeight abi.DealWeight, err error) {
|
||||||
|
w, vw, _, err := market2.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch)
|
||||||
|
return w, vw, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type balanceTable2 struct {
|
||||||
|
*adt2.BalanceTable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bt *balanceTable2) ForEach(cb func(address.Address, abi.TokenAmount) error) error {
|
||||||
|
asMap := (*adt2.Map)(bt.BalanceTable)
|
||||||
|
var ta abi.TokenAmount
|
||||||
|
return asMap.ForEach(&ta, func(key string) error {
|
||||||
|
a, err := address.NewFromBytes([]byte(key))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return cb(a, ta)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type dealStates2 struct {
|
||||||
|
adt.Array
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *dealStates2) Get(dealID abi.DealID) (*DealState, bool, error) {
|
||||||
|
var deal2 market2.DealState
|
||||||
|
found, err := s.Array.Get(uint64(dealID), &deal2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
deal := fromV2DealState(deal2)
|
||||||
|
return &deal, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *dealStates2) ForEach(cb func(dealID abi.DealID, ds DealState) error) error {
|
||||||
|
var ds1 market2.DealState
|
||||||
|
return s.Array.ForEach(&ds1, func(idx int64) error {
|
||||||
|
return cb(abi.DealID(idx), fromV2DealState(ds1))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *dealStates2) decode(val *cbg.Deferred) (*DealState, error) {
|
||||||
|
var ds1 market2.DealState
|
||||||
|
if err := ds1.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ds := fromV2DealState(ds1)
|
||||||
|
return &ds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *dealStates2) array() adt.Array {
|
||||||
|
return s.Array
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromV2DealState(v1 market2.DealState) DealState {
|
||||||
|
return (DealState)(v1)
|
||||||
|
}
|
||||||
|
|
||||||
|
type dealProposals2 struct {
|
||||||
|
adt.Array
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *dealProposals2) Get(dealID abi.DealID) (*DealProposal, bool, error) {
|
||||||
|
var proposal2 market2.DealProposal
|
||||||
|
found, err := s.Array.Get(uint64(dealID), &proposal2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
proposal := fromV2DealProposal(proposal2)
|
||||||
|
return &proposal, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *dealProposals2) ForEach(cb func(dealID abi.DealID, dp DealProposal) error) error {
|
||||||
|
var dp1 market2.DealProposal
|
||||||
|
return s.Array.ForEach(&dp1, func(idx int64) error {
|
||||||
|
return cb(abi.DealID(idx), fromV2DealProposal(dp1))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *dealProposals2) decode(val *cbg.Deferred) (*DealProposal, error) {
|
||||||
|
var dp1 market2.DealProposal
|
||||||
|
if err := dp1.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dp := fromV2DealProposal(dp1)
|
||||||
|
return &dp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *dealProposals2) array() adt.Array {
|
||||||
|
return s.Array
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromV2DealProposal(v1 market2.DealProposal) DealProposal {
|
||||||
|
return (DealProposal)(v1)
|
||||||
|
}
|
180
chain/actors/builtin/miner/diff_deadlines.go
Normal file
180
chain/actors/builtin/miner/diff_deadlines.go
Normal file
@ -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
|
||||||
|
}
|
@ -11,14 +11,26 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/cbor"
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
"github.com/filecoin-project/go-state-types/dline"
|
"github.com/filecoin-project/go-state-types/dline"
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
|
||||||
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Unchanged between v0 and v1 actors
|
func init() {
|
||||||
|
builtin.RegisterActorState(builtin0.StorageMinerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load0(store, root)
|
||||||
|
})
|
||||||
|
builtin.RegisterActorState(builtin2.StorageMinerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load2(store, root)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unchanged between v0 and v2 actors
|
||||||
var WPoStProvingPeriod = miner0.WPoStProvingPeriod
|
var WPoStProvingPeriod = miner0.WPoStProvingPeriod
|
||||||
var WPoStPeriodDeadlines = miner0.WPoStPeriodDeadlines
|
var WPoStPeriodDeadlines = miner0.WPoStPeriodDeadlines
|
||||||
var WPoStChallengeWindow = miner0.WPoStChallengeWindow
|
var WPoStChallengeWindow = miner0.WPoStChallengeWindow
|
||||||
@ -30,12 +42,9 @@ const MinSectorExpiration = miner0.MinSectorExpiration
|
|||||||
func Load(store adt.Store, act *types.Actor) (st State, err error) {
|
func Load(store adt.Store, act *types.Actor) (st State, err error) {
|
||||||
switch act.Code {
|
switch act.Code {
|
||||||
case builtin0.StorageMinerActorCodeID:
|
case builtin0.StorageMinerActorCodeID:
|
||||||
out := state0{store: store}
|
return load0(store, act.Head)
|
||||||
err := store.Get(store.Context(), act.Head, &out)
|
case builtin2.StorageMinerActorCodeID:
|
||||||
if err != nil {
|
return load2(store, act.Head)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &out, nil
|
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||||
}
|
}
|
||||||
@ -49,6 +58,7 @@ type State interface {
|
|||||||
VestedFunds(abi.ChainEpoch) (abi.TokenAmount, error)
|
VestedFunds(abi.ChainEpoch) (abi.TokenAmount, error)
|
||||||
// Funds locked for various reasons.
|
// Funds locked for various reasons.
|
||||||
LockedFunds() (LockedFunds, error)
|
LockedFunds() (LockedFunds, error)
|
||||||
|
FeeDebt() (abi.TokenAmount, error)
|
||||||
|
|
||||||
GetSector(abi.SectorNumber) (*SectorOnChainInfo, error)
|
GetSector(abi.SectorNumber) (*SectorOnChainInfo, error)
|
||||||
FindSector(abi.SectorNumber) (*SectorLocation, error)
|
FindSector(abi.SectorNumber) (*SectorLocation, error)
|
||||||
@ -135,6 +145,7 @@ type MinerInfo struct {
|
|||||||
SealProofType abi.RegisteredSealProof
|
SealProofType abi.RegisteredSealProof
|
||||||
SectorSize abi.SectorSize
|
SectorSize abi.SectorSize
|
||||||
WindowPoStPartitionSectors uint64
|
WindowPoStPartitionSectors uint64
|
||||||
|
ConsensusFaultElapsed abi.ChainEpoch
|
||||||
}
|
}
|
||||||
|
|
||||||
type SectorExpiration struct {
|
type SectorExpiration struct {
|
||||||
|
@ -4,22 +4,34 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-bitfield"
|
"github.com/filecoin-project/go-bitfield"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/dline"
|
"github.com/filecoin-project/go-state-types/dline"
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
"github.com/ipfs/go-cid"
|
||||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
|
||||||
|
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ State = (*state0)(nil)
|
var _ State = (*state0)(nil)
|
||||||
|
|
||||||
|
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state0{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
type state0 struct {
|
type state0 struct {
|
||||||
miner0.State
|
miner0.State
|
||||||
store adt.Store
|
store adt.Store
|
||||||
@ -51,6 +63,10 @@ func (s *state0) LockedFunds() (LockedFunds, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *state0) FeeDebt() (abi.TokenAmount, error) {
|
||||||
|
return big.Zero(), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *state0) InitialPledge() (abi.TokenAmount, error) {
|
func (s *state0) InitialPledge() (abi.TokenAmount, error) {
|
||||||
return s.State.InitialPledgeRequirement, nil
|
return s.State.InitialPledgeRequirement, nil
|
||||||
}
|
}
|
||||||
@ -277,6 +293,7 @@ func (s *state0) Info() (MinerInfo, error) {
|
|||||||
SealProofType: info.SealProofType,
|
SealProofType: info.SealProofType,
|
||||||
SectorSize: info.SectorSize,
|
SectorSize: info.SectorSize,
|
||||||
WindowPoStPartitionSectors: info.WindowPoStPartitionSectors,
|
WindowPoStPartitionSectors: info.WindowPoStPartitionSectors,
|
||||||
|
ConsensusFaultElapsed: -1,
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.PendingWorkerKey != nil {
|
if info.PendingWorkerKey != nil {
|
||||||
|
407
chain/actors/builtin/miner/v2.go
Normal file
407
chain/actors/builtin/miner/v2.go
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
package miner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-bitfield"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/go-state-types/dline"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
|
||||||
|
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
|
||||||
|
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ State = (*state2)(nil)
|
||||||
|
|
||||||
|
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state2{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type state2 struct {
|
||||||
|
miner2.State
|
||||||
|
store adt.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
type deadline2 struct {
|
||||||
|
miner2.Deadline
|
||||||
|
store adt.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
type partition2 struct {
|
||||||
|
miner2.Partition
|
||||||
|
store adt.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) AvailableBalance(bal abi.TokenAmount) (abi.TokenAmount, error) {
|
||||||
|
return s.GetAvailableBalance(bal)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) {
|
||||||
|
return s.CheckVestedFunds(s.store, epoch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) LockedFunds() (LockedFunds, error) {
|
||||||
|
return LockedFunds{
|
||||||
|
VestingFunds: s.State.LockedFunds,
|
||||||
|
InitialPledgeRequirement: s.State.InitialPledge,
|
||||||
|
PreCommitDeposits: s.State.PreCommitDeposits,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) FeeDebt() (abi.TokenAmount, error) {
|
||||||
|
return s.State.FeeDebt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) InitialPledge() (abi.TokenAmount, error) {
|
||||||
|
return s.State.InitialPledge, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) PreCommitDeposits() (abi.TokenAmount, error) {
|
||||||
|
return s.State.PreCommitDeposits, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) {
|
||||||
|
info, ok, err := s.State.GetSector(s.store, num)
|
||||||
|
if !ok || err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := fromV2SectorOnChainInfo(*info)
|
||||||
|
return &ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) FindSector(num abi.SectorNumber) (*SectorLocation, error) {
|
||||||
|
dlIdx, partIdx, err := s.State.FindSector(s.store, num)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &SectorLocation{
|
||||||
|
Deadline: dlIdx,
|
||||||
|
Partition: partIdx,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) NumLiveSectors() (uint64, error) {
|
||||||
|
dls, err := s.State.LoadDeadlines(s.store)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
var total uint64
|
||||||
|
if err := dls.ForEach(s.store, func(dlIdx uint64, dl *miner2.Deadline) error {
|
||||||
|
total += dl.LiveSectors
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSectorExpiration returns the effective expiration of the given sector.
|
||||||
|
//
|
||||||
|
// If the sector does not expire early, the Early expiration field is 0.
|
||||||
|
func (s *state2) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, error) {
|
||||||
|
dls, err := s.State.LoadDeadlines(s.store)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// NOTE: this can be optimized significantly.
|
||||||
|
// 1. If the sector is non-faulty, it will either expire on-time (can be
|
||||||
|
// learned from the sector info), or in the next quantized expiration
|
||||||
|
// epoch (i.e., the first element in the partition's expiration queue.
|
||||||
|
// 2. If it's faulty, it will expire early within the first 14 entries
|
||||||
|
// of the expiration queue.
|
||||||
|
stopErr := errors.New("stop")
|
||||||
|
out := SectorExpiration{}
|
||||||
|
err = dls.ForEach(s.store, func(dlIdx uint64, dl *miner2.Deadline) error {
|
||||||
|
partitions, err := dl.PartitionsArray(s.store)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
quant := s.State.QuantSpecForDeadline(dlIdx)
|
||||||
|
var part miner2.Partition
|
||||||
|
return partitions.ForEach(&part, func(partIdx int64) error {
|
||||||
|
if found, err := part.Sectors.IsSet(uint64(num)); err != nil {
|
||||||
|
return err
|
||||||
|
} else if !found {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if found, err := part.Terminated.IsSet(uint64(num)); err != nil {
|
||||||
|
return err
|
||||||
|
} else if found {
|
||||||
|
// already terminated
|
||||||
|
return stopErr
|
||||||
|
}
|
||||||
|
|
||||||
|
q, err := miner2.LoadExpirationQueue(s.store, part.ExpirationsEpochs, quant)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var exp miner2.ExpirationSet
|
||||||
|
return q.ForEach(&exp, func(epoch int64) error {
|
||||||
|
if early, err := exp.EarlySectors.IsSet(uint64(num)); err != nil {
|
||||||
|
return err
|
||||||
|
} else if early {
|
||||||
|
out.Early = abi.ChainEpoch(epoch)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if onTime, err := exp.OnTimeSectors.IsSet(uint64(num)); err != nil {
|
||||||
|
return err
|
||||||
|
} else if onTime {
|
||||||
|
out.OnTime = abi.ChainEpoch(epoch)
|
||||||
|
return stopErr
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if err == stopErr {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if out.Early == 0 && out.OnTime == 0 {
|
||||||
|
return nil, xerrors.Errorf("failed to find sector %d", num)
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) {
|
||||||
|
info, ok, err := s.State.GetPrecommittedSector(s.store, num)
|
||||||
|
if !ok || err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := fromV2SectorPreCommitOnChainInfo(*info)
|
||||||
|
|
||||||
|
return &ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) LoadSectors(snos *bitfield.BitField) ([]*SectorOnChainInfo, error) {
|
||||||
|
sectors, err := miner2.LoadSectors(s.store, s.State.Sectors)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no sector numbers are specified, load all.
|
||||||
|
if snos == nil {
|
||||||
|
infos := make([]*SectorOnChainInfo, 0, sectors.Length())
|
||||||
|
var info2 miner2.SectorOnChainInfo
|
||||||
|
if err := sectors.ForEach(&info2, func(_ int64) error {
|
||||||
|
info := fromV2SectorOnChainInfo(info2)
|
||||||
|
infos = append(infos, &info)
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return infos, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, load selected.
|
||||||
|
infos2, err := sectors.Load(*snos)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
infos := make([]*SectorOnChainInfo, len(infos2))
|
||||||
|
for i, info2 := range infos2 {
|
||||||
|
info := fromV2SectorOnChainInfo(*info2)
|
||||||
|
infos[i] = &info
|
||||||
|
}
|
||||||
|
return infos, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) IsAllocated(num abi.SectorNumber) (bool, error) {
|
||||||
|
var allocatedSectors bitfield.BitField
|
||||||
|
if err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return allocatedSectors.IsSet(uint64(num))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) LoadDeadline(idx uint64) (Deadline, error) {
|
||||||
|
dls, err := s.State.LoadDeadlines(s.store)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dl, err := dls.LoadDeadline(s.store, idx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &deadline2{*dl, s.store}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) ForEachDeadline(cb func(uint64, Deadline) error) error {
|
||||||
|
dls, err := s.State.LoadDeadlines(s.store)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return dls.ForEach(s.store, func(i uint64, dl *miner2.Deadline) error {
|
||||||
|
return cb(i, &deadline2{*dl, s.store})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) NumDeadlines() (uint64, error) {
|
||||||
|
return miner2.WPoStPeriodDeadlines, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) DeadlinesChanged(other State) (bool, error) {
|
||||||
|
other2, ok := other.(*state2)
|
||||||
|
if !ok {
|
||||||
|
// treat an upgrade as a change, always
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.State.Deadlines.Equals(other2.Deadlines), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) Info() (MinerInfo, error) {
|
||||||
|
info, err := s.State.GetInfo(s.store)
|
||||||
|
if err != nil {
|
||||||
|
return MinerInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pid *peer.ID
|
||||||
|
if peerID, err := peer.IDFromBytes(info.PeerId); err == nil {
|
||||||
|
pid = &peerID
|
||||||
|
}
|
||||||
|
|
||||||
|
mi := MinerInfo{
|
||||||
|
Owner: info.Owner,
|
||||||
|
Worker: info.Worker,
|
||||||
|
ControlAddresses: info.ControlAddresses,
|
||||||
|
|
||||||
|
NewWorker: address.Undef,
|
||||||
|
WorkerChangeEpoch: -1,
|
||||||
|
|
||||||
|
PeerId: pid,
|
||||||
|
Multiaddrs: info.Multiaddrs,
|
||||||
|
SealProofType: info.SealProofType,
|
||||||
|
SectorSize: info.SectorSize,
|
||||||
|
WindowPoStPartitionSectors: info.WindowPoStPartitionSectors,
|
||||||
|
ConsensusFaultElapsed: info.ConsensusFaultElapsed,
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.PendingWorkerKey != nil {
|
||||||
|
mi.NewWorker = info.PendingWorkerKey.NewWorker
|
||||||
|
mi.WorkerChangeEpoch = info.PendingWorkerKey.EffectiveAt
|
||||||
|
}
|
||||||
|
|
||||||
|
return mi, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) {
|
||||||
|
return s.State.DeadlineInfo(epoch), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) sectors() (adt.Array, error) {
|
||||||
|
return adt2.AsArray(s.store, s.Sectors)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) decodeSectorOnChainInfo(val *cbg.Deferred) (SectorOnChainInfo, error) {
|
||||||
|
var si miner2.SectorOnChainInfo
|
||||||
|
err := si.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||||
|
if err != nil {
|
||||||
|
return SectorOnChainInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fromV2SectorOnChainInfo(si), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) precommits() (adt.Map, error) {
|
||||||
|
return adt2.AsMap(s.store, s.PreCommittedSectors)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) {
|
||||||
|
var sp miner2.SectorPreCommitOnChainInfo
|
||||||
|
err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||||
|
if err != nil {
|
||||||
|
return SectorPreCommitOnChainInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fromV2SectorPreCommitOnChainInfo(sp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deadline2) LoadPartition(idx uint64) (Partition, error) {
|
||||||
|
p, err := d.Deadline.LoadPartition(d.store, idx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &partition2{*p, d.store}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deadline2) ForEachPartition(cb func(uint64, Partition) error) error {
|
||||||
|
ps, err := d.Deadline.PartitionsArray(d.store)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var part miner2.Partition
|
||||||
|
return ps.ForEach(&part, func(i int64) error {
|
||||||
|
return cb(uint64(i), &partition2{part, d.store})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deadline2) PartitionsChanged(other Deadline) (bool, error) {
|
||||||
|
other2, ok := other.(*deadline2)
|
||||||
|
if !ok {
|
||||||
|
// treat an upgrade as a change, always
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.Deadline.Partitions.Equals(other2.Deadline.Partitions), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deadline2) PostSubmissions() (bitfield.BitField, error) {
|
||||||
|
return d.Deadline.PostSubmissions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *partition2) AllSectors() (bitfield.BitField, error) {
|
||||||
|
return p.Partition.Sectors, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *partition2) FaultySectors() (bitfield.BitField, error) {
|
||||||
|
return p.Partition.Faults, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *partition2) RecoveringSectors() (bitfield.BitField, error) {
|
||||||
|
return p.Partition.Recoveries, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromV2SectorOnChainInfo(v2 miner2.SectorOnChainInfo) SectorOnChainInfo {
|
||||||
|
return SectorOnChainInfo{
|
||||||
|
SectorNumber: v2.SectorNumber,
|
||||||
|
SealProof: v2.SealProof,
|
||||||
|
SealedCID: v2.SealedCID,
|
||||||
|
DealIDs: v2.DealIDs,
|
||||||
|
Activation: v2.Activation,
|
||||||
|
Expiration: v2.Expiration,
|
||||||
|
DealWeight: v2.DealWeight,
|
||||||
|
VerifiedDealWeight: v2.VerifiedDealWeight,
|
||||||
|
InitialPledge: v2.InitialPledge,
|
||||||
|
ExpectedDayReward: v2.ExpectedDayReward,
|
||||||
|
ExpectedStoragePledge: v2.ExpectedStoragePledge,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromV2SectorPreCommitOnChainInfo(v2 miner2.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo {
|
||||||
|
return SectorPreCommitOnChainInfo{
|
||||||
|
Info: (SectorPreCommitInfo)(v2.Info),
|
||||||
|
PreCommitDeposit: v2.PreCommitDeposit,
|
||||||
|
PreCommitEpoch: v2.PreCommitEpoch,
|
||||||
|
DealWeight: v2.DealWeight,
|
||||||
|
VerifiedDealWeight: v2.VerifiedDealWeight,
|
||||||
|
}
|
||||||
|
}
|
70
chain/actors/builtin/multisig/message.go
Normal file
70
chain/actors/builtin/multisig/message.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package multisig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/minio/blake2b-simd"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
|
multisig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Message(version actors.Version, from address.Address) MessageBuilder {
|
||||||
|
switch version {
|
||||||
|
case actors.Version0:
|
||||||
|
return message0{from}
|
||||||
|
case actors.Version2:
|
||||||
|
return message2{message0{from}}
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unsupported actors version: %d", version))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageBuilder interface {
|
||||||
|
// Create a new multisig with the specified parameters.
|
||||||
|
Create(signers []address.Address, threshold uint64,
|
||||||
|
vestingStart, vestingDuration abi.ChainEpoch,
|
||||||
|
initialAmount abi.TokenAmount) (*types.Message, error)
|
||||||
|
|
||||||
|
// Propose a transaction to the given multisig.
|
||||||
|
Propose(msig, target address.Address, amt abi.TokenAmount,
|
||||||
|
method abi.MethodNum, params []byte) (*types.Message, error)
|
||||||
|
|
||||||
|
// Approve a multisig transaction. The "hash" is optional.
|
||||||
|
Approve(msig address.Address, txID uint64, hash *ProposalHashData) (*types.Message, error)
|
||||||
|
|
||||||
|
// Cancel a multisig transaction. The "hash" is optional.
|
||||||
|
Cancel(msig address.Address, txID uint64, hash *ProposalHashData) (*types.Message, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this type is the same between v0 and v2
|
||||||
|
type ProposalHashData = multisig2.ProposalHashData
|
||||||
|
|
||||||
|
func txnParams(id uint64, data *ProposalHashData) ([]byte, error) {
|
||||||
|
params := multisig2.TxnIDParams{ID: multisig2.TxnID(id)}
|
||||||
|
if data != nil {
|
||||||
|
if data.Requester.Protocol() != address.ID {
|
||||||
|
return nil, xerrors.Errorf("proposer address must be an ID address, was %s", data.Requester)
|
||||||
|
}
|
||||||
|
if data.Value.Sign() == -1 {
|
||||||
|
return nil, xerrors.Errorf("proposal value must be non-negative, was %s", data.Value)
|
||||||
|
}
|
||||||
|
if data.To == address.Undef {
|
||||||
|
return nil, xerrors.Errorf("proposed destination address must be set")
|
||||||
|
}
|
||||||
|
pser, err := data.Serialize()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hash := blake2b.Sum256(pser)
|
||||||
|
params.ProposalHash = hash[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return actors.SerializeParams(¶ms)
|
||||||
|
}
|
142
chain/actors/builtin/multisig/message0.go
Normal file
142
chain/actors/builtin/multisig/message0.go
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
package multisig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||||
|
multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type message0 struct{ from address.Address }
|
||||||
|
|
||||||
|
func (m message0) Create(
|
||||||
|
signers []address.Address, threshold uint64,
|
||||||
|
unlockStart, unlockDuration abi.ChainEpoch,
|
||||||
|
initialAmount abi.TokenAmount,
|
||||||
|
) (*types.Message, error) {
|
||||||
|
|
||||||
|
lenAddrs := uint64(len(signers))
|
||||||
|
|
||||||
|
if lenAddrs < threshold {
|
||||||
|
return nil, xerrors.Errorf("cannot require signing of more addresses than provided for multisig")
|
||||||
|
}
|
||||||
|
|
||||||
|
if threshold == 0 {
|
||||||
|
threshold = lenAddrs
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.from == address.Undef {
|
||||||
|
return nil, xerrors.Errorf("must provide source address")
|
||||||
|
}
|
||||||
|
|
||||||
|
if unlockStart != 0 {
|
||||||
|
return nil, xerrors.Errorf("actors v0 does not support a non-zero vesting start time")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up constructor parameters for multisig
|
||||||
|
msigParams := &multisig0.ConstructorParams{
|
||||||
|
Signers: signers,
|
||||||
|
NumApprovalsThreshold: threshold,
|
||||||
|
UnlockDuration: unlockDuration,
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, actErr := actors.SerializeParams(msigParams)
|
||||||
|
if actErr != nil {
|
||||||
|
return nil, actErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// new actors are created by invoking 'exec' on the init actor with the constructor params
|
||||||
|
execParams := &init0.ExecParams{
|
||||||
|
CodeCID: builtin0.MultisigActorCodeID,
|
||||||
|
ConstructorParams: enc,
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, actErr = actors.SerializeParams(execParams)
|
||||||
|
if actErr != nil {
|
||||||
|
return nil, actErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: init_.Address,
|
||||||
|
From: m.from,
|
||||||
|
Method: builtin0.MethodsInit.Exec,
|
||||||
|
Params: enc,
|
||||||
|
Value: initialAmount,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m message0) Propose(msig, to address.Address, amt abi.TokenAmount,
|
||||||
|
method abi.MethodNum, params []byte) (*types.Message, error) {
|
||||||
|
|
||||||
|
if msig == address.Undef {
|
||||||
|
return nil, xerrors.Errorf("must provide a multisig address for proposal")
|
||||||
|
}
|
||||||
|
|
||||||
|
if to == address.Undef {
|
||||||
|
return nil, xerrors.Errorf("must provide a target address for proposal")
|
||||||
|
}
|
||||||
|
|
||||||
|
if amt.Sign() == -1 {
|
||||||
|
return nil, xerrors.Errorf("must provide a non-negative amount for proposed send")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.from == address.Undef {
|
||||||
|
return nil, xerrors.Errorf("must provide source address")
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, actErr := actors.SerializeParams(&multisig0.ProposeParams{
|
||||||
|
To: to,
|
||||||
|
Value: amt,
|
||||||
|
Method: method,
|
||||||
|
Params: params,
|
||||||
|
})
|
||||||
|
if actErr != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to serialize parameters: %w", actErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: msig,
|
||||||
|
From: m.from,
|
||||||
|
Value: abi.NewTokenAmount(0),
|
||||||
|
Method: builtin0.MethodsMultisig.Propose,
|
||||||
|
Params: enc,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m message0) Approve(msig address.Address, txID uint64, hashData *ProposalHashData) (*types.Message, error) {
|
||||||
|
enc, err := txnParams(txID, hashData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: msig,
|
||||||
|
From: m.from,
|
||||||
|
Value: types.NewInt(0),
|
||||||
|
Method: builtin0.MethodsMultisig.Approve,
|
||||||
|
Params: enc,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m message0) Cancel(msig address.Address, txID uint64, hashData *ProposalHashData) (*types.Message, error) {
|
||||||
|
enc, err := txnParams(txID, hashData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: msig,
|
||||||
|
From: m.from,
|
||||||
|
Value: types.NewInt(0),
|
||||||
|
Method: builtin0.MethodsMultisig.Cancel,
|
||||||
|
Params: enc,
|
||||||
|
}, nil
|
||||||
|
}
|
71
chain/actors/builtin/multisig/message2.go
Normal file
71
chain/actors/builtin/multisig/message2.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package multisig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init"
|
||||||
|
multisig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type message2 struct{ message0 }
|
||||||
|
|
||||||
|
func (m message2) Create(
|
||||||
|
signers []address.Address, threshold uint64,
|
||||||
|
unlockStart, unlockDuration abi.ChainEpoch,
|
||||||
|
initialAmount abi.TokenAmount,
|
||||||
|
) (*types.Message, error) {
|
||||||
|
|
||||||
|
lenAddrs := uint64(len(signers))
|
||||||
|
|
||||||
|
if lenAddrs < threshold {
|
||||||
|
return nil, xerrors.Errorf("cannot require signing of more addresses than provided for multisig")
|
||||||
|
}
|
||||||
|
|
||||||
|
if threshold == 0 {
|
||||||
|
threshold = lenAddrs
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.from == address.Undef {
|
||||||
|
return nil, xerrors.Errorf("must provide source address")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up constructor parameters for multisig
|
||||||
|
msigParams := &multisig2.ConstructorParams{
|
||||||
|
Signers: signers,
|
||||||
|
NumApprovalsThreshold: threshold,
|
||||||
|
UnlockDuration: unlockDuration,
|
||||||
|
StartEpoch: unlockStart,
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, actErr := actors.SerializeParams(msigParams)
|
||||||
|
if actErr != nil {
|
||||||
|
return nil, actErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// new actors are created by invoking 'exec' on the init actor with the constructor params
|
||||||
|
execParams := &init2.ExecParams{
|
||||||
|
CodeCID: builtin2.MultisigActorCodeID,
|
||||||
|
ConstructorParams: enc,
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, actErr = actors.SerializeParams(execParams)
|
||||||
|
if actErr != nil {
|
||||||
|
return nil, actErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: init_.Address,
|
||||||
|
From: m.from,
|
||||||
|
Method: builtin2.MethodsInit.Exec,
|
||||||
|
Params: enc,
|
||||||
|
Value: initialAmount,
|
||||||
|
}, nil
|
||||||
|
}
|
@ -6,23 +6,32 @@ import (
|
|||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/cbor"
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
builtin.RegisterActorState(builtin0.MultisigActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load0(store, root)
|
||||||
|
})
|
||||||
|
builtin.RegisterActorState(builtin2.MultisigActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load2(store, root)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func Load(store adt.Store, act *types.Actor) (State, error) {
|
func Load(store adt.Store, act *types.Actor) (State, error) {
|
||||||
switch act.Code {
|
switch act.Code {
|
||||||
case builtin0.MultisigActorCodeID:
|
case builtin0.MultisigActorCodeID:
|
||||||
out := state0{store: store}
|
return load0(store, act.Head)
|
||||||
err := store.Get(store.Context(), act.Head, &out)
|
case builtin2.MultisigActorCodeID:
|
||||||
if err != nil {
|
return load2(store, act.Head)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &out, nil
|
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||||
}
|
}
|
@ -5,15 +5,26 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/ipfs/go-cid"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
|
||||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ State = (*state0)(nil)
|
var _ State = (*state0)(nil)
|
||||||
|
|
||||||
|
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state0{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
type state0 struct {
|
type state0 struct {
|
||||||
msig0.State
|
msig0.State
|
||||||
store adt.Store
|
store adt.Store
|
70
chain/actors/builtin/multisig/state2.go
Normal file
70
chain/actors/builtin/multisig/state2.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package multisig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
|
||||||
|
msig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig"
|
||||||
|
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ State = (*state2)(nil)
|
||||||
|
|
||||||
|
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state2{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type state2 struct {
|
||||||
|
msig2.State
|
||||||
|
store adt.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) LockedBalance(currEpoch abi.ChainEpoch) (abi.TokenAmount, error) {
|
||||||
|
return s.State.AmountLocked(currEpoch - s.State.StartEpoch), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) StartEpoch() (abi.ChainEpoch, error) {
|
||||||
|
return s.State.StartEpoch, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) UnlockDuration() (abi.ChainEpoch, error) {
|
||||||
|
return s.State.UnlockDuration, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) InitialBalance() (abi.TokenAmount, error) {
|
||||||
|
return s.State.InitialBalance, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) Threshold() (uint64, error) {
|
||||||
|
return s.State.NumApprovalsThreshold, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) Signers() ([]address.Address, error) {
|
||||||
|
return s.State.Signers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) ForEachPendingTxn(cb func(id int64, txn Transaction) error) error {
|
||||||
|
arr, err := adt2.AsMap(s.store, s.State.PendingTxns)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var out msig2.Transaction
|
||||||
|
return arr.ForEach(&out, func(key string) error {
|
||||||
|
txid, n := binary.Varint([]byte(key))
|
||||||
|
if n <= 0 {
|
||||||
|
return xerrors.Errorf("invalid pending transaction key: %v", key)
|
||||||
|
}
|
||||||
|
return cb(txid, (Transaction)(out))
|
||||||
|
})
|
||||||
|
}
|
28
chain/actors/builtin/paych/message.go
Normal file
28
chain/actors/builtin/paych/message.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package paych
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Message(version actors.Version, from address.Address) MessageBuilder {
|
||||||
|
switch version {
|
||||||
|
case actors.Version0:
|
||||||
|
return message0{from}
|
||||||
|
case actors.Version2:
|
||||||
|
return message2{from}
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unsupported actors version: %d", version))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageBuilder interface {
|
||||||
|
Create(to address.Address, initialAmount abi.TokenAmount) (*types.Message, error)
|
||||||
|
Update(paych address.Address, voucher *SignedVoucher, secret []byte) (*types.Message, error)
|
||||||
|
Settle(paych address.Address) (*types.Message, error)
|
||||||
|
Collect(paych address.Address) (*types.Message, error)
|
||||||
|
}
|
74
chain/actors/builtin/paych/message0.go
Normal file
74
chain/actors/builtin/paych/message0.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package paych
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||||
|
paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type message0 struct{ from address.Address }
|
||||||
|
|
||||||
|
func (m message0) Create(to address.Address, initialAmount abi.TokenAmount) (*types.Message, error) {
|
||||||
|
params, aerr := actors.SerializeParams(&paych0.ConstructorParams{From: m.from, To: to})
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
enc, aerr := actors.SerializeParams(&init0.ExecParams{
|
||||||
|
CodeCID: builtin0.PaymentChannelActorCodeID,
|
||||||
|
ConstructorParams: params,
|
||||||
|
})
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: init_.Address,
|
||||||
|
From: m.from,
|
||||||
|
Value: initialAmount,
|
||||||
|
Method: builtin0.MethodsInit.Exec,
|
||||||
|
Params: enc,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m message0) Update(paych address.Address, sv *SignedVoucher, secret []byte) (*types.Message, error) {
|
||||||
|
params, aerr := actors.SerializeParams(&paych0.UpdateChannelStateParams{
|
||||||
|
Sv: *sv,
|
||||||
|
Secret: secret,
|
||||||
|
})
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: paych,
|
||||||
|
From: m.from,
|
||||||
|
Value: abi.NewTokenAmount(0),
|
||||||
|
Method: builtin0.MethodsPaych.UpdateChannelState,
|
||||||
|
Params: params,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m message0) Settle(paych address.Address) (*types.Message, error) {
|
||||||
|
return &types.Message{
|
||||||
|
To: paych,
|
||||||
|
From: m.from,
|
||||||
|
Value: abi.NewTokenAmount(0),
|
||||||
|
Method: builtin0.MethodsPaych.Settle,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m message0) Collect(paych address.Address) (*types.Message, error) {
|
||||||
|
return &types.Message{
|
||||||
|
To: paych,
|
||||||
|
From: m.from,
|
||||||
|
Value: abi.NewTokenAmount(0),
|
||||||
|
Method: builtin0.MethodsPaych.Collect,
|
||||||
|
}, nil
|
||||||
|
}
|
74
chain/actors/builtin/paych/message2.go
Normal file
74
chain/actors/builtin/paych/message2.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package paych
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init"
|
||||||
|
paych2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/paych"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type message2 struct{ from address.Address }
|
||||||
|
|
||||||
|
func (m message2) Create(to address.Address, initialAmount abi.TokenAmount) (*types.Message, error) {
|
||||||
|
params, aerr := actors.SerializeParams(&paych2.ConstructorParams{From: m.from, To: to})
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
enc, aerr := actors.SerializeParams(&init2.ExecParams{
|
||||||
|
CodeCID: builtin2.PaymentChannelActorCodeID,
|
||||||
|
ConstructorParams: params,
|
||||||
|
})
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: init_.Address,
|
||||||
|
From: m.from,
|
||||||
|
Value: initialAmount,
|
||||||
|
Method: builtin2.MethodsInit.Exec,
|
||||||
|
Params: enc,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m message2) Update(paych address.Address, sv *SignedVoucher, secret []byte) (*types.Message, error) {
|
||||||
|
params, aerr := actors.SerializeParams(&paych2.UpdateChannelStateParams{
|
||||||
|
Sv: *sv,
|
||||||
|
Secret: secret,
|
||||||
|
})
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: paych,
|
||||||
|
From: m.from,
|
||||||
|
Value: abi.NewTokenAmount(0),
|
||||||
|
Method: builtin2.MethodsPaych.UpdateChannelState,
|
||||||
|
Params: params,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m message2) Settle(paych address.Address) (*types.Message, error) {
|
||||||
|
return &types.Message{
|
||||||
|
To: paych,
|
||||||
|
From: m.from,
|
||||||
|
Value: abi.NewTokenAmount(0),
|
||||||
|
Method: builtin2.MethodsPaych.Settle,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m message2) Collect(paych address.Address) (*types.Message, error) {
|
||||||
|
return &types.Message{
|
||||||
|
To: paych,
|
||||||
|
From: m.from,
|
||||||
|
Value: abi.NewTokenAmount(0),
|
||||||
|
Method: builtin2.MethodsPaych.Collect,
|
||||||
|
}, nil
|
||||||
|
}
|
@ -1,29 +1,42 @@
|
|||||||
package paych
|
package paych
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
big "github.com/filecoin-project/go-state-types/big"
|
big "github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/go-state-types/cbor"
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
ipldcbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
builtin.RegisterActorState(builtin0.PaymentChannelActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load0(store, root)
|
||||||
|
})
|
||||||
|
builtin.RegisterActorState(builtin2.PaymentChannelActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load2(store, root)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Load returns an abstract copy of payment channel state, irregardless of actor version
|
// Load returns an abstract copy of payment channel state, irregardless of actor version
|
||||||
func Load(store adt.Store, act *types.Actor) (State, error) {
|
func Load(store adt.Store, act *types.Actor) (State, error) {
|
||||||
switch act.Code {
|
switch act.Code {
|
||||||
case builtin0.PaymentChannelActorCodeID:
|
case builtin0.PaymentChannelActorCodeID:
|
||||||
out := state0{store: store}
|
return load0(store, act.Head)
|
||||||
err := store.Get(store.Context(), act.Head, &out)
|
case builtin2.PaymentChannelActorCodeID:
|
||||||
if err != nil {
|
return load2(store, act.Head)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &out, nil
|
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||||
}
|
}
|
||||||
@ -58,3 +71,18 @@ type LaneState interface {
|
|||||||
|
|
||||||
type SignedVoucher = paych0.SignedVoucher
|
type SignedVoucher = paych0.SignedVoucher
|
||||||
type ModVerifyParams = paych0.ModVerifyParams
|
type ModVerifyParams = paych0.ModVerifyParams
|
||||||
|
|
||||||
|
// DecodeSignedVoucher decodes base64 encoded signed voucher.
|
||||||
|
func DecodeSignedVoucher(s string) (*SignedVoucher, error) {
|
||||||
|
data, err := base64.RawURLEncoding.DecodeString(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var sv SignedVoucher
|
||||||
|
if err := ipldcbor.DecodeInto(data, &sv); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &sv, nil
|
||||||
|
}
|
@ -1,18 +1,31 @@
|
|||||||
package paych
|
package paych
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
big "github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
||||||
|
paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ State = (*state0)(nil)
|
var _ State = (*state0)(nil)
|
||||||
|
|
||||||
|
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state0{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
type state0 struct {
|
type state0 struct {
|
||||||
paych.State
|
paych0.State
|
||||||
store adt.Store
|
store adt.Store
|
||||||
lsAmt *adt0.Array
|
lsAmt *adt0.Array
|
||||||
}
|
}
|
||||||
@ -72,14 +85,14 @@ func (s *state0) ForEachLaneState(cb func(idx uint64, dl LaneState) error) error
|
|||||||
// Note: we use a map instead of an array to store laneStates because the
|
// Note: we use a map instead of an array to store laneStates because the
|
||||||
// client sets the lane ID (the index) and potentially they could use a
|
// client sets the lane ID (the index) and potentially they could use a
|
||||||
// very large index.
|
// very large index.
|
||||||
var ls paych.LaneState
|
var ls paych0.LaneState
|
||||||
return lsamt.ForEach(&ls, func(i int64) error {
|
return lsamt.ForEach(&ls, func(i int64) error {
|
||||||
return cb(uint64(i), &laneState0{ls})
|
return cb(uint64(i), &laneState0{ls})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type laneState0 struct {
|
type laneState0 struct {
|
||||||
paych.LaneState
|
paych0.LaneState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *laneState0) Redeemed() (big.Int, error) {
|
func (ls *laneState0) Redeemed() (big.Int, error) {
|
104
chain/actors/builtin/paych/state2.go
Normal file
104
chain/actors/builtin/paych/state2.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package paych
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
|
||||||
|
paych2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/paych"
|
||||||
|
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ State = (*state2)(nil)
|
||||||
|
|
||||||
|
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state2{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type state2 struct {
|
||||||
|
paych2.State
|
||||||
|
store adt.Store
|
||||||
|
lsAmt *adt2.Array
|
||||||
|
}
|
||||||
|
|
||||||
|
// Channel owner, who has funded the actor
|
||||||
|
func (s *state2) From() (address.Address, error) {
|
||||||
|
return s.State.From, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recipient of payouts from channel
|
||||||
|
func (s *state2) To() (address.Address, error) {
|
||||||
|
return s.State.To, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Height at which the channel can be `Collected`
|
||||||
|
func (s *state2) SettlingAt() (abi.ChainEpoch, error) {
|
||||||
|
return s.State.SettlingAt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Amount successfully redeemed through the payment channel, paid out on `Collect()`
|
||||||
|
func (s *state2) ToSend() (abi.TokenAmount, error) {
|
||||||
|
return s.State.ToSend, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) getOrLoadLsAmt() (*adt2.Array, error) {
|
||||||
|
if s.lsAmt != nil {
|
||||||
|
return s.lsAmt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the lane state from the chain
|
||||||
|
lsamt, err := adt2.AsArray(s.store, s.State.LaneStates)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.lsAmt = lsamt
|
||||||
|
return lsamt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get total number of lanes
|
||||||
|
func (s *state2) LaneCount() (uint64, error) {
|
||||||
|
lsamt, err := s.getOrLoadLsAmt()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return lsamt.Length(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate lane states
|
||||||
|
func (s *state2) ForEachLaneState(cb func(idx uint64, dl LaneState) error) error {
|
||||||
|
// Get the lane state from the chain
|
||||||
|
lsamt, err := s.getOrLoadLsAmt()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: we use a map instead of an array to store laneStates because the
|
||||||
|
// client sets the lane ID (the index) and potentially they could use a
|
||||||
|
// very large index.
|
||||||
|
var ls paych2.LaneState
|
||||||
|
return lsamt.ForEach(&ls, func(i int64) error {
|
||||||
|
return cb(uint64(i), &laneState2{ls})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type laneState2 struct {
|
||||||
|
paych2.LaneState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *laneState2) Redeemed() (big.Int, error) {
|
||||||
|
return ls.LaneState.Redeemed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *laneState2) Nonce() (uint64, error) {
|
||||||
|
return ls.LaneState.Nonce, nil
|
||||||
|
}
|
@ -2,28 +2,37 @@ package power
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/cbor"
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
|
||||||
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
builtin.RegisterActorState(builtin0.StoragePowerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load0(store, root)
|
||||||
|
})
|
||||||
|
builtin.RegisterActorState(builtin2.StoragePowerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load2(store, root)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
var Address = builtin0.StoragePowerActorAddr
|
var Address = builtin0.StoragePowerActorAddr
|
||||||
|
|
||||||
func Load(store adt.Store, act *types.Actor) (st State, err error) {
|
func Load(store adt.Store, act *types.Actor) (st State, err error) {
|
||||||
switch act.Code {
|
switch act.Code {
|
||||||
case builtin0.StoragePowerActorCodeID:
|
case builtin0.StoragePowerActorCodeID:
|
||||||
out := state0{store: store}
|
return load0(store, act.Head)
|
||||||
err := store.Get(store.Context(), act.Head, &out)
|
case builtin2.StoragePowerActorCodeID:
|
||||||
if err != nil {
|
return load2(store, act.Head)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &out, nil
|
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,26 @@ package power
|
|||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ State = (*state0)(nil)
|
var _ State = (*state0)(nil)
|
||||||
|
|
||||||
|
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state0{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
type state0 struct {
|
type state0 struct {
|
||||||
power0.State
|
power0.State
|
||||||
store adt.Store
|
store adt.Store
|
||||||
@ -35,7 +48,7 @@ func (s *state0) TotalCommitted() (Claim, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *state0) MinerPower(addr address.Address) (Claim, bool, error) {
|
func (s *state0) MinerPower(addr address.Address) (Claim, bool, error) {
|
||||||
claims, err := adt.AsMap(s.store, s.Claims)
|
claims, err := adt0.AsMap(s.store, s.Claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Claim{}, false, err
|
return Claim{}, false, err
|
||||||
}
|
}
|
||||||
@ -63,7 +76,7 @@ func (s *state0) MinerCounts() (uint64, uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *state0) ListAllMiners() ([]address.Address, error) {
|
func (s *state0) ListAllMiners() ([]address.Address, error) {
|
||||||
claims, err := adt.AsMap(s.store, s.Claims)
|
claims, err := adt0.AsMap(s.store, s.Claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
98
chain/actors/builtin/power/v2.go
Normal file
98
chain/actors/builtin/power/v2.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package power
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
|
power2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/power"
|
||||||
|
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ State = (*state2)(nil)
|
||||||
|
|
||||||
|
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state2{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type state2 struct {
|
||||||
|
power2.State
|
||||||
|
store adt.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) TotalLocked() (abi.TokenAmount, error) {
|
||||||
|
return s.TotalPledgeCollateral, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) TotalPower() (Claim, error) {
|
||||||
|
return Claim{
|
||||||
|
RawBytePower: s.TotalRawBytePower,
|
||||||
|
QualityAdjPower: s.TotalQualityAdjPower,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Committed power to the network. Includes miners below the minimum threshold.
|
||||||
|
func (s *state2) TotalCommitted() (Claim, error) {
|
||||||
|
return Claim{
|
||||||
|
RawBytePower: s.TotalBytesCommitted,
|
||||||
|
QualityAdjPower: s.TotalQABytesCommitted,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) MinerPower(addr address.Address) (Claim, bool, error) {
|
||||||
|
claims, err := adt2.AsMap(s.store, s.Claims)
|
||||||
|
if err != nil {
|
||||||
|
return Claim{}, false, err
|
||||||
|
}
|
||||||
|
var claim power2.Claim
|
||||||
|
ok, err := claims.Get(abi.AddrKey(addr), &claim)
|
||||||
|
if err != nil {
|
||||||
|
return Claim{}, false, err
|
||||||
|
}
|
||||||
|
return Claim{
|
||||||
|
RawBytePower: claim.RawBytePower,
|
||||||
|
QualityAdjPower: claim.QualityAdjPower,
|
||||||
|
}, ok, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) MinerNominalPowerMeetsConsensusMinimum(a address.Address) (bool, error) {
|
||||||
|
return s.State.MinerNominalPowerMeetsConsensusMinimum(s.store, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) TotalPowerSmoothed() (builtin.FilterEstimate, error) {
|
||||||
|
return builtin.FromV2FilterEstimate(s.State.ThisEpochQAPowerSmoothed), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) MinerCounts() (uint64, uint64, error) {
|
||||||
|
return uint64(s.State.MinerAboveMinPowerCount), uint64(s.State.MinerCount), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) ListAllMiners() ([]address.Address, error) {
|
||||||
|
claims, err := adt2.AsMap(s.store, s.Claims)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var miners []address.Address
|
||||||
|
err = claims.ForEach(nil, func(k string) error {
|
||||||
|
a, err := address.NewFromBytes([]byte(k))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
miners = append(miners, a)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return miners, nil
|
||||||
|
}
|
@ -3,27 +3,35 @@ package reward
|
|||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/cbor"
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
builtin.RegisterActorState(builtin0.RewardActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load0(store, root)
|
||||||
|
})
|
||||||
|
builtin.RegisterActorState(builtin2.RewardActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load2(store, root)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
var Address = builtin0.RewardActorAddr
|
var Address = builtin0.RewardActorAddr
|
||||||
|
|
||||||
func Load(store adt.Store, act *types.Actor) (st State, err error) {
|
func Load(store adt.Store, act *types.Actor) (st State, err error) {
|
||||||
switch act.Code {
|
switch act.Code {
|
||||||
case builtin0.RewardActorCodeID:
|
case builtin0.RewardActorCodeID:
|
||||||
out := state0{store: store}
|
return load0(store, act.Head)
|
||||||
err := store.Get(store.Context(), act.Head, &out)
|
case builtin2.RewardActorCodeID:
|
||||||
if err != nil {
|
return load2(store, act.Head)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &out, nil
|
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,29 @@ package reward
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing"
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/smoothing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ State = (*state0)(nil)
|
var _ State = (*state0)(nil)
|
||||||
|
|
||||||
|
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state0{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
type state0 struct {
|
type state0 struct {
|
||||||
reward.State
|
reward0.State
|
||||||
store adt.Store
|
store adt.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +66,7 @@ func (s *state0) InitialPledgeForPower(sectorWeight abi.StoragePower, networkTot
|
|||||||
s.State.ThisEpochBaselinePower,
|
s.State.ThisEpochBaselinePower,
|
||||||
networkTotalPledge,
|
networkTotalPledge,
|
||||||
s.State.ThisEpochRewardSmoothed,
|
s.State.ThisEpochRewardSmoothed,
|
||||||
&smoothing.FilterEstimate{
|
&smoothing0.FilterEstimate{
|
||||||
PositionEstimate: networkQAPower.PositionEstimate,
|
PositionEstimate: networkQAPower.PositionEstimate,
|
||||||
VelocityEstimate: networkQAPower.VelocityEstimate,
|
VelocityEstimate: networkQAPower.VelocityEstimate,
|
||||||
},
|
},
|
||||||
@ -63,7 +75,7 @@ func (s *state0) InitialPledgeForPower(sectorWeight abi.StoragePower, networkTot
|
|||||||
|
|
||||||
func (s *state0) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, sectorWeight abi.StoragePower) (abi.TokenAmount, error) {
|
func (s *state0) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, sectorWeight abi.StoragePower) (abi.TokenAmount, error) {
|
||||||
return miner0.PreCommitDepositForPower(s.State.ThisEpochRewardSmoothed,
|
return miner0.PreCommitDepositForPower(s.State.ThisEpochRewardSmoothed,
|
||||||
&smoothing.FilterEstimate{
|
&smoothing0.FilterEstimate{
|
||||||
PositionEstimate: networkQAPower.PositionEstimate,
|
PositionEstimate: networkQAPower.PositionEstimate,
|
||||||
VelocityEstimate: networkQAPower.VelocityEstimate,
|
VelocityEstimate: networkQAPower.VelocityEstimate,
|
||||||
},
|
},
|
||||||
|
86
chain/actors/builtin/reward/v2.go
Normal file
86
chain/actors/builtin/reward/v2.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package reward
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
|
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
|
||||||
|
reward2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/reward"
|
||||||
|
smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ State = (*state2)(nil)
|
||||||
|
|
||||||
|
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state2{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type state2 struct {
|
||||||
|
reward2.State
|
||||||
|
store adt.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) ThisEpochReward() (abi.StoragePower, error) {
|
||||||
|
return s.State.ThisEpochReward, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) ThisEpochRewardSmoothed() (builtin.FilterEstimate, error) {
|
||||||
|
return builtin.FilterEstimate{
|
||||||
|
PositionEstimate: s.State.ThisEpochRewardSmoothed.PositionEstimate,
|
||||||
|
VelocityEstimate: s.State.ThisEpochRewardSmoothed.VelocityEstimate,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) ThisEpochBaselinePower() (abi.StoragePower, error) {
|
||||||
|
return s.State.ThisEpochBaselinePower, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) TotalStoragePowerReward() (abi.TokenAmount, error) {
|
||||||
|
return s.State.TotalStoragePowerReward, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) EffectiveBaselinePower() (abi.StoragePower, error) {
|
||||||
|
return s.State.EffectiveBaselinePower, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) EffectiveNetworkTime() (abi.ChainEpoch, error) {
|
||||||
|
return s.State.EffectiveNetworkTime, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) CumsumBaseline() (abi.StoragePower, error) {
|
||||||
|
return s.State.CumsumBaseline, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) CumsumRealized() (abi.StoragePower, error) {
|
||||||
|
return s.State.CumsumBaseline, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) InitialPledgeForPower(qaPower abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) {
|
||||||
|
return miner2.InitialPledgeForPower(
|
||||||
|
qaPower,
|
||||||
|
s.State.ThisEpochBaselinePower,
|
||||||
|
s.State.ThisEpochRewardSmoothed,
|
||||||
|
smoothing2.FilterEstimate{
|
||||||
|
PositionEstimate: networkQAPower.PositionEstimate,
|
||||||
|
VelocityEstimate: networkQAPower.VelocityEstimate,
|
||||||
|
},
|
||||||
|
circSupply,
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, sectorWeight abi.StoragePower) (abi.TokenAmount, error) {
|
||||||
|
return miner2.PreCommitDepositForPower(s.State.ThisEpochRewardSmoothed,
|
||||||
|
smoothing2.FilterEstimate{
|
||||||
|
PositionEstimate: networkQAPower.PositionEstimate,
|
||||||
|
VelocityEstimate: networkQAPower.VelocityEstimate,
|
||||||
|
},
|
||||||
|
sectorWeight), nil
|
||||||
|
}
|
46
chain/actors/builtin/verifreg/util.go
Normal file
46
chain/actors/builtin/verifreg/util.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package verifreg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getDataCap(store adt.Store, ver actors.Version, root cid.Cid, addr address.Address) (bool, abi.StoragePower, error) {
|
||||||
|
if addr.Protocol() != address.ID {
|
||||||
|
return false, big.Zero(), xerrors.Errorf("can only look up ID addresses")
|
||||||
|
}
|
||||||
|
|
||||||
|
vh, err := adt.AsMap(store, root, ver)
|
||||||
|
if err != nil {
|
||||||
|
return false, big.Zero(), xerrors.Errorf("loading verifreg: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dcap abi.StoragePower
|
||||||
|
if found, err := vh.Get(abi.AddrKey(addr), &dcap); err != nil {
|
||||||
|
return false, big.Zero(), xerrors.Errorf("looking up addr: %w", err)
|
||||||
|
} else if !found {
|
||||||
|
return false, big.Zero(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, dcap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func forEachCap(store adt.Store, ver actors.Version, root cid.Cid, cb func(addr address.Address, dcap abi.StoragePower) error) error {
|
||||||
|
vh, err := adt.AsMap(store, root, ver)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("loading verified clients: %w", err)
|
||||||
|
}
|
||||||
|
var dcap abi.StoragePower
|
||||||
|
return vh.ForEach(&dcap, func(key string) error {
|
||||||
|
a, err := address.NewFromBytes([]byte(key))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return cb(a, dcap)
|
||||||
|
})
|
||||||
|
}
|
@ -3,73 +3,46 @@ package verifreg
|
|||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
|
||||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
|
||||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
|
||||||
|
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ State = (*state0)(nil)
|
var _ State = (*state0)(nil)
|
||||||
|
|
||||||
|
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state0{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
type state0 struct {
|
type state0 struct {
|
||||||
verifreg0.State
|
verifreg0.State
|
||||||
store adt.Store
|
store adt.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDataCap(store adt.Store, root cid.Cid, addr address.Address) (bool, abi.StoragePower, error) {
|
|
||||||
if addr.Protocol() != address.ID {
|
|
||||||
return false, big.Zero(), xerrors.Errorf("can only look up ID addresses")
|
|
||||||
}
|
|
||||||
|
|
||||||
vh, err := adt0.AsMap(store, root)
|
|
||||||
if err != nil {
|
|
||||||
return false, big.Zero(), xerrors.Errorf("loading verifreg: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var dcap abi.StoragePower
|
|
||||||
if found, err := vh.Get(abi.AddrKey(addr), &dcap); err != nil {
|
|
||||||
return false, big.Zero(), xerrors.Errorf("looking up addr: %w", err)
|
|
||||||
} else if !found {
|
|
||||||
return false, big.Zero(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, dcap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state0) RootKey() (address.Address, error) {
|
func (s *state0) RootKey() (address.Address, error) {
|
||||||
return s.State.RootKey, nil
|
return s.State.RootKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state0) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) {
|
func (s *state0) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) {
|
||||||
return getDataCap(s.store, s.State.VerifiedClients, addr)
|
return getDataCap(s.store, actors.Version0, s.State.VerifiedClients, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state0) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, error) {
|
func (s *state0) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, error) {
|
||||||
return getDataCap(s.store, s.State.Verifiers, addr)
|
return getDataCap(s.store, actors.Version0, s.State.Verifiers, addr)
|
||||||
}
|
|
||||||
|
|
||||||
func forEachCap(store adt.Store, root cid.Cid, cb func(addr address.Address, dcap abi.StoragePower) error) error {
|
|
||||||
vh, err := adt0.AsMap(store, root)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("loading verified clients: %w", err)
|
|
||||||
}
|
|
||||||
var dcap abi.StoragePower
|
|
||||||
return vh.ForEach(&dcap, func(key string) error {
|
|
||||||
a, err := address.NewFromBytes([]byte(key))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return cb(a, dcap)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state0) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error {
|
func (s *state0) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error {
|
||||||
return forEachCap(s.store, s.State.Verifiers, cb)
|
return forEachCap(s.store, actors.Version0, s.State.Verifiers, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state0) ForEachClient(cb func(addr address.Address, dcap abi.StoragePower) error) error {
|
func (s *state0) ForEachClient(cb func(addr address.Address, dcap abi.StoragePower) error) error {
|
||||||
return forEachCap(s.store, s.State.VerifiedClients, cb)
|
return forEachCap(s.store, actors.Version0, s.State.VerifiedClients, cb)
|
||||||
}
|
}
|
||||||
|
48
chain/actors/builtin/verifreg/v2.go
Normal file
48
chain/actors/builtin/verifreg/v2.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package verifreg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
|
||||||
|
verifreg2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/verifreg"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ State = (*state2)(nil)
|
||||||
|
|
||||||
|
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||||
|
out := state2{store: store}
|
||||||
|
err := store.Get(store.Context(), root, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type state2 struct {
|
||||||
|
verifreg2.State
|
||||||
|
store adt.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) RootKey() (address.Address, error) {
|
||||||
|
return s.State.RootKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) {
|
||||||
|
return getDataCap(s.store, actors.Version2, s.State.VerifiedClients, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, error) {
|
||||||
|
return getDataCap(s.store, actors.Version2, s.State.Verifiers, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error {
|
||||||
|
return forEachCap(s.store, actors.Version2, s.State.Verifiers, cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state2) ForEachClient(cb func(addr address.Address, dcap abi.StoragePower) error) error {
|
||||||
|
return forEachCap(s.store, actors.Version2, s.State.VerifiedClients, cb)
|
||||||
|
}
|
@ -3,26 +3,35 @@ package verifreg
|
|||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/cbor"
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
builtin.RegisterActorState(builtin0.VerifiedRegistryActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load0(store, root)
|
||||||
|
})
|
||||||
|
builtin.RegisterActorState(builtin2.VerifiedRegistryActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||||
|
return load2(store, root)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
var Address = builtin0.VerifiedRegistryActorAddr
|
var Address = builtin0.VerifiedRegistryActorAddr
|
||||||
|
|
||||||
func Load(store adt.Store, act *types.Actor) (State, error) {
|
func Load(store adt.Store, act *types.Actor) (State, error) {
|
||||||
switch act.Code {
|
switch act.Code {
|
||||||
case builtin0.VerifiedRegistryActorCodeID:
|
case builtin0.VerifiedRegistryActorCodeID:
|
||||||
out := state0{store: store}
|
return load0(store, act.Head)
|
||||||
err := store.Get(store.Context(), act.Head, &out)
|
case builtin2.VerifiedRegistryActorCodeID:
|
||||||
if err != nil {
|
return load2(store, act.Head)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &out, nil
|
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,21 @@ package policy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market"
|
||||||
|
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
|
||||||
|
verifreg2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/verifreg"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ChainFinality = miner0.ChainFinality
|
||||||
|
SealRandomnessLookback = ChainFinality
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetSupportedProofTypes sets supported proof types, across all actor versions.
|
// SetSupportedProofTypes sets supported proof types, across all actor versions.
|
||||||
@ -17,6 +28,7 @@ func SetSupportedProofTypes(types ...abi.RegisteredSealProof) {
|
|||||||
}
|
}
|
||||||
// Set for all miner versions.
|
// Set for all miner versions.
|
||||||
miner0.SupportedProofTypes = newTypes
|
miner0.SupportedProofTypes = newTypes
|
||||||
|
miner2.SupportedProofTypes = newTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSupportedProofTypes sets supported proof types, across all actor versions.
|
// AddSupportedProofTypes sets supported proof types, across all actor versions.
|
||||||
@ -25,6 +37,7 @@ func AddSupportedProofTypes(types ...abi.RegisteredSealProof) {
|
|||||||
for _, t := range types {
|
for _, t := range types {
|
||||||
// Set for all miner versions.
|
// Set for all miner versions.
|
||||||
miner0.SupportedProofTypes[t] = struct{}{}
|
miner0.SupportedProofTypes[t] = struct{}{}
|
||||||
|
miner2.SupportedProofTypes[t] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +46,7 @@ func AddSupportedProofTypes(types ...abi.RegisteredSealProof) {
|
|||||||
func SetPreCommitChallengeDelay(delay abi.ChainEpoch) {
|
func SetPreCommitChallengeDelay(delay abi.ChainEpoch) {
|
||||||
// Set for all miner versions.
|
// Set for all miner versions.
|
||||||
miner0.PreCommitChallengeDelay = delay
|
miner0.PreCommitChallengeDelay = delay
|
||||||
|
miner2.PreCommitChallengeDelay = delay
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this function shouldn't really exist. Instead, the API should expose the precommit delay.
|
// TODO: this function shouldn't really exist. Instead, the API should expose the precommit delay.
|
||||||
@ -45,10 +59,58 @@ func GetPreCommitChallengeDelay() abi.ChainEpoch {
|
|||||||
// for testing.
|
// for testing.
|
||||||
func SetConsensusMinerMinPower(p abi.StoragePower) {
|
func SetConsensusMinerMinPower(p abi.StoragePower) {
|
||||||
power0.ConsensusMinerMinPower = p
|
power0.ConsensusMinerMinPower = p
|
||||||
|
for _, policy := range builtin2.SealProofPolicies {
|
||||||
|
policy.ConsensusMinerMinPower = p
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMinVerifiedDealSize sets the minimum size of a verified deal. This should
|
// SetMinVerifiedDealSize sets the minimum size of a verified deal. This should
|
||||||
// only be used for testing.
|
// only be used for testing.
|
||||||
func SetMinVerifiedDealSize(size abi.StoragePower) {
|
func SetMinVerifiedDealSize(size abi.StoragePower) {
|
||||||
verifreg0.MinVerifiedDealSize = size
|
verifreg0.MinVerifiedDealSize = size
|
||||||
|
verifreg2.MinVerifiedDealSize = size
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) abi.ChainEpoch {
|
||||||
|
switch ver {
|
||||||
|
case actors.Version0:
|
||||||
|
return miner0.MaxSealDuration[t]
|
||||||
|
case actors.Version2:
|
||||||
|
return miner2.MaxProveCommitDuration[t]
|
||||||
|
default:
|
||||||
|
panic("unsupported actors version")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DealProviderCollateralBounds(
|
||||||
|
size abi.PaddedPieceSize, verified bool,
|
||||||
|
rawBytePower, qaPower, baselinePower abi.StoragePower,
|
||||||
|
circulatingFil abi.TokenAmount, nwVer network.Version,
|
||||||
|
) (min, max abi.TokenAmount) {
|
||||||
|
switch actors.VersionForNetwork(nwVer) {
|
||||||
|
case actors.Version0:
|
||||||
|
return market0.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil, nwVer)
|
||||||
|
case actors.Version2:
|
||||||
|
return market2.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil)
|
||||||
|
default:
|
||||||
|
panic("unsupported network version")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the challenge window and scales the proving period to match (such that
|
||||||
|
// there are always 48 challenge windows in a proving period).
|
||||||
|
func SetWPoStChallengeWindow(period abi.ChainEpoch) {
|
||||||
|
miner0.WPoStChallengeWindow = period
|
||||||
|
miner0.WPoStProvingPeriod = period * abi.ChainEpoch(miner0.WPoStPeriodDeadlines)
|
||||||
|
|
||||||
|
miner2.WPoStChallengeWindow = period
|
||||||
|
miner2.WPoStProvingPeriod = period * abi.ChainEpoch(miner2.WPoStPeriodDeadlines)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetWinningPoStSectorSetLookback(nwVer network.Version) abi.ChainEpoch {
|
||||||
|
if nwVer <= network.Version3 {
|
||||||
|
return 10
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChainFinality
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
|
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||||
|
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
|
||||||
|
verifreg2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/verifreg"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSupportedProofTypes(t *testing.T) {
|
func TestSupportedProofTypes(t *testing.T) {
|
||||||
@ -34,3 +37,14 @@ func TestSupportedProofTypes(t *testing.T) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests assumptions about policies being the same between actor versions.
|
||||||
|
func TestAssumptions(t *testing.T) {
|
||||||
|
require.EqualValues(t, miner0.SupportedProofTypes, miner2.SupportedProofTypes)
|
||||||
|
require.Equal(t, miner0.PreCommitChallengeDelay, miner2.PreCommitChallengeDelay)
|
||||||
|
require.Equal(t, miner0.ChainFinality, miner2.ChainFinality)
|
||||||
|
require.Equal(t, miner0.WPoStChallengeWindow, miner2.WPoStChallengeWindow)
|
||||||
|
require.Equal(t, miner0.WPoStProvingPeriod, miner2.WPoStProvingPeriod)
|
||||||
|
require.Equal(t, miner0.WPoStPeriodDeadlines, miner2.WPoStPeriodDeadlines)
|
||||||
|
require.True(t, verifreg0.MinVerifiedDealSize.Equals(verifreg2.MinVerifiedDealSize))
|
||||||
|
}
|
||||||
|
26
chain/actors/version.go
Normal file
26
chain/actors/version.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package actors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Version int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Version0 Version = 0
|
||||||
|
Version2 Version = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// Converts a network version into an actors adt version.
|
||||||
|
func VersionForNetwork(version network.Version) Version {
|
||||||
|
switch version {
|
||||||
|
case network.Version0, network.Version1, network.Version2, network.Version3:
|
||||||
|
return Version0
|
||||||
|
case network.Version4:
|
||||||
|
return Version2
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unsupported network version %d", version))
|
||||||
|
}
|
||||||
|
}
|
@ -117,7 +117,7 @@ func (c *client) doRequest(
|
|||||||
res, err := c.sendRequestToPeer(ctx, peer, req)
|
res, err := c.sendRequestToPeer(ctx, peer, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !xerrors.Is(err, network.ErrNoConn) {
|
if !xerrors.Is(err, network.ErrNoConn) {
|
||||||
log.Warnf("could not connect to peer %s: %s",
|
log.Warnf("could not send request to peer %s: %s",
|
||||||
peer.String(), err)
|
peer.String(), err)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
@ -224,7 +225,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
|||||||
},
|
},
|
||||||
VerifregRootKey: DefaultVerifregRootkeyActor,
|
VerifregRootKey: DefaultVerifregRootkeyActor,
|
||||||
RemainderAccount: DefaultRemainderAccountActor,
|
RemainderAccount: DefaultRemainderAccountActor,
|
||||||
NetworkName: "",
|
NetworkName: uuid.New().String(),
|
||||||
Timestamp: uint64(build.Clock.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()),
|
Timestamp: uint64(build.Clock.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
@ -24,7 +26,6 @@ import (
|
|||||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -115,7 +116,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
|||||||
return nil, nil, xerrors.Errorf("putting empty object: %w", err)
|
return nil, nil, xerrors.Errorf("putting empty object: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
state, err := state.NewStateTree(cst, builtin.Version0)
|
state, err := state.NewStateTree(cst, types.StateTreeVersion0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
|
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
|
||||||
}
|
}
|
||||||
@ -296,14 +297,9 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
|||||||
return nil, nil, xerrors.Errorf("somehow overallocated filecoin (allocated = %s)", types.FIL(totalFilAllocated))
|
return nil, nil, xerrors.Errorf("somehow overallocated filecoin (allocated = %s)", types.FIL(totalFilAllocated))
|
||||||
}
|
}
|
||||||
|
|
||||||
remAccKey, err := address.NewIDAddress(90)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
template.RemainderAccount.Balance = remainingFil
|
template.RemainderAccount.Balance = remainingFil
|
||||||
|
|
||||||
if err := createMultisigAccount(ctx, bs, cst, state, remAccKey, template.RemainderAccount, keyIDs); err != nil {
|
if err := createMultisigAccount(ctx, bs, cst, state, builtin.ReserveAddress, template.RemainderAccount, keyIDs); err != nil {
|
||||||
return nil, nil, xerrors.Errorf("failed to set up remainder account: %w", err)
|
return nil, nil, xerrors.Errorf("failed to set up remainder account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,9 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ActorLookup func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error)
|
type ActorLookup func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error)
|
||||||
@ -27,19 +29,33 @@ type CostKey struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var Costs = map[CostKey]int64{
|
var Costs = map[CostKey]int64{
|
||||||
{builtin.InitActorCodeID, 2}: 8916753,
|
{builtin0.InitActorCodeID, 2}: 8916753,
|
||||||
{builtin.StorageMarketActorCodeID, 2}: 6955002,
|
{builtin0.StorageMarketActorCodeID, 2}: 6955002,
|
||||||
{builtin.StorageMarketActorCodeID, 4}: 245436108,
|
{builtin0.StorageMarketActorCodeID, 4}: 245436108,
|
||||||
{builtin.StorageMinerActorCodeID, 4}: 2315133,
|
{builtin0.StorageMinerActorCodeID, 4}: 2315133,
|
||||||
{builtin.StorageMinerActorCodeID, 5}: 1600271356,
|
{builtin0.StorageMinerActorCodeID, 5}: 1600271356,
|
||||||
{builtin.StorageMinerActorCodeID, 6}: 22864493,
|
{builtin0.StorageMinerActorCodeID, 6}: 22864493,
|
||||||
{builtin.StorageMinerActorCodeID, 7}: 142002419,
|
{builtin0.StorageMinerActorCodeID, 7}: 142002419,
|
||||||
{builtin.StorageMinerActorCodeID, 10}: 23008274,
|
{builtin0.StorageMinerActorCodeID, 10}: 23008274,
|
||||||
{builtin.StorageMinerActorCodeID, 11}: 19303178,
|
{builtin0.StorageMinerActorCodeID, 11}: 19303178,
|
||||||
{builtin.StorageMinerActorCodeID, 14}: 566356835,
|
{builtin0.StorageMinerActorCodeID, 14}: 566356835,
|
||||||
{builtin.StorageMinerActorCodeID, 16}: 5325185,
|
{builtin0.StorageMinerActorCodeID, 16}: 5325185,
|
||||||
{builtin.StorageMinerActorCodeID, 18}: 2328637,
|
{builtin0.StorageMinerActorCodeID, 18}: 2328637,
|
||||||
{builtin.StoragePowerActorCodeID, 2}: 23600956,
|
{builtin0.StoragePowerActorCodeID, 2}: 23600956,
|
||||||
|
// TODO: Just reuse v0 values for now, this isn't actually used
|
||||||
|
{builtin2.InitActorCodeID, 2}: 8916753,
|
||||||
|
{builtin2.StorageMarketActorCodeID, 2}: 6955002,
|
||||||
|
{builtin2.StorageMarketActorCodeID, 4}: 245436108,
|
||||||
|
{builtin2.StorageMinerActorCodeID, 4}: 2315133,
|
||||||
|
{builtin2.StorageMinerActorCodeID, 5}: 1600271356,
|
||||||
|
{builtin2.StorageMinerActorCodeID, 6}: 22864493,
|
||||||
|
{builtin2.StorageMinerActorCodeID, 7}: 142002419,
|
||||||
|
{builtin2.StorageMinerActorCodeID, 10}: 23008274,
|
||||||
|
{builtin2.StorageMinerActorCodeID, 11}: 19303178,
|
||||||
|
{builtin2.StorageMinerActorCodeID, 14}: 566356835,
|
||||||
|
{builtin2.StorageMinerActorCodeID, 16}: 5325185,
|
||||||
|
{builtin2.StorageMinerActorCodeID, 18}: 2328637,
|
||||||
|
{builtin2.StoragePowerActorCodeID, 2}: 23600956,
|
||||||
}
|
}
|
||||||
|
|
||||||
func failedGuess(msg *types.SignedMessage) int64 {
|
func failedGuess(msg *types.SignedMessage) int64 {
|
||||||
@ -51,7 +67,8 @@ func failedGuess(msg *types.SignedMessage) int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GuessGasUsed(ctx context.Context, tsk types.TipSetKey, msg *types.SignedMessage, al ActorLookup) (int64, error) {
|
func GuessGasUsed(ctx context.Context, tsk types.TipSetKey, msg *types.SignedMessage, al ActorLookup) (int64, error) {
|
||||||
if msg.Message.Method == builtin.MethodSend {
|
// MethodSend is the same in all versions.
|
||||||
|
if msg.Message.Method == builtin0.MethodSend {
|
||||||
switch msg.Message.From.Protocol() {
|
switch msg.Message.From.Protocol() {
|
||||||
case address.BLS:
|
case address.BLS:
|
||||||
return 1298450, nil
|
return 1298450, nil
|
||||||
|
@ -3,6 +3,7 @@ package messagesigner
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||||
@ -16,7 +17,7 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const dsKeyActorNonce = "ActorNonce"
|
const dsKeyActorNonce = "ActorNextNonce"
|
||||||
|
|
||||||
var log = logging.Logger("messagesigner")
|
var log = logging.Logger("messagesigner")
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ type mpoolAPI interface {
|
|||||||
// when signing a message
|
// when signing a message
|
||||||
type MessageSigner struct {
|
type MessageSigner struct {
|
||||||
wallet *wallet.Wallet
|
wallet *wallet.Wallet
|
||||||
|
lk sync.Mutex
|
||||||
mpool mpoolAPI
|
mpool mpoolAPI
|
||||||
ds datastore.Batching
|
ds datastore.Batching
|
||||||
}
|
}
|
||||||
@ -47,25 +49,42 @@ func newMessageSigner(wallet *wallet.Wallet, mpool mpoolAPI, ds dtypes.MetadataD
|
|||||||
|
|
||||||
// SignMessage increments the nonce for the message From address, and signs
|
// SignMessage increments the nonce for the message From address, and signs
|
||||||
// the message
|
// the message
|
||||||
func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message) (*types.SignedMessage, error) {
|
func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message, cb func(*types.SignedMessage) error) (*types.SignedMessage, error) {
|
||||||
|
ms.lk.Lock()
|
||||||
|
defer ms.lk.Unlock()
|
||||||
|
|
||||||
|
// Get the next message nonce
|
||||||
nonce, err := ms.nextNonce(msg.From)
|
nonce, err := ms.nextNonce(msg.From)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to create nonce: %w", err)
|
return nil, xerrors.Errorf("failed to create nonce: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sign the message with the nonce
|
||||||
msg.Nonce = nonce
|
msg.Nonce = nonce
|
||||||
sig, err := ms.wallet.Sign(ctx, msg.From, msg.Cid().Bytes())
|
sig, err := ms.wallet.Sign(ctx, msg.From, msg.Cid().Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to sign message: %w", err)
|
return nil, xerrors.Errorf("failed to sign message: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &types.SignedMessage{
|
// Callback with the signed message
|
||||||
|
smsg := &types.SignedMessage{
|
||||||
Message: *msg,
|
Message: *msg,
|
||||||
Signature: *sig,
|
Signature: *sig,
|
||||||
}, nil
|
}
|
||||||
|
err = cb(smsg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the callback executed successfully, write the nonce to the datastore
|
||||||
|
if err := ms.saveNonce(msg.From, nonce); err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to save nonce: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return smsg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// nextNonce increments the nonce.
|
// nextNonce gets the next nonce for the given address.
|
||||||
// If there is no nonce in the datastore, gets the nonce from the message pool.
|
// If there is no nonce in the datastore, gets the nonce from the message pool.
|
||||||
func (ms *MessageSigner) nextNonce(addr address.Address) (uint64, error) {
|
func (ms *MessageSigner) nextNonce(addr address.Address) (uint64, error) {
|
||||||
// Nonces used to be created by the mempool and we need to support nodes
|
// Nonces used to be created by the mempool and we need to support nodes
|
||||||
@ -77,21 +96,22 @@ func (ms *MessageSigner) nextNonce(addr address.Address) (uint64, error) {
|
|||||||
return 0, xerrors.Errorf("failed to get nonce from mempool: %w", err)
|
return 0, xerrors.Errorf("failed to get nonce from mempool: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the nonce for this address from the datastore
|
// Get the next nonce for this address from the datastore
|
||||||
addrNonceKey := datastore.KeyWithNamespaces([]string{dsKeyActorNonce, addr.String()})
|
addrNonceKey := ms.dstoreKey(addr)
|
||||||
dsNonceBytes, err := ms.ds.Get(addrNonceKey)
|
dsNonceBytes, err := ms.ds.Get(addrNonceKey)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case xerrors.Is(err, datastore.ErrNotFound):
|
case xerrors.Is(err, datastore.ErrNotFound):
|
||||||
// If a nonce for this address hasn't yet been created in the
|
// If a nonce for this address hasn't yet been created in the
|
||||||
// datastore, just use the nonce from the mempool
|
// datastore, just use the nonce from the mempool
|
||||||
|
return nonce, nil
|
||||||
|
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return 0, xerrors.Errorf("failed to get nonce from datastore: %w", err)
|
return 0, xerrors.Errorf("failed to get nonce from datastore: %w", err)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// There is a nonce in the datastore, so unmarshall and increment it
|
// There is a nonce in the datastore, so unmarshall it
|
||||||
maj, val, err := cbg.CborReadHeader(bytes.NewReader(dsNonceBytes))
|
maj, dsNonce, err := cbg.CborReadHeader(bytes.NewReader(dsNonceBytes))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, xerrors.Errorf("failed to parse nonce from datastore: %w", err)
|
return 0, xerrors.Errorf("failed to parse nonce from datastore: %w", err)
|
||||||
}
|
}
|
||||||
@ -99,26 +119,37 @@ func (ms *MessageSigner) nextNonce(addr address.Address) (uint64, error) {
|
|||||||
return 0, xerrors.Errorf("bad cbor type parsing nonce from datastore")
|
return 0, xerrors.Errorf("bad cbor type parsing nonce from datastore")
|
||||||
}
|
}
|
||||||
|
|
||||||
dsNonce := val + 1
|
|
||||||
|
|
||||||
// The message pool nonce should be <= than the datastore nonce
|
// The message pool nonce should be <= than the datastore nonce
|
||||||
if nonce <= dsNonce {
|
if nonce <= dsNonce {
|
||||||
nonce = dsNonce
|
nonce = dsNonce
|
||||||
} else {
|
} else {
|
||||||
log.Warnf("mempool nonce was larger than datastore nonce (%d > %d)", nonce, dsNonce)
|
log.Warnf("mempool nonce was larger than datastore nonce (%d > %d)", nonce, dsNonce)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Write the nonce for this address to the datastore
|
return nonce, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// saveNonce increments the nonce for this address and writes it to the
|
||||||
|
// datastore
|
||||||
|
func (ms *MessageSigner) saveNonce(addr address.Address, nonce uint64) error {
|
||||||
|
// Increment the nonce
|
||||||
|
nonce++
|
||||||
|
|
||||||
|
// Write the nonce to the datastore
|
||||||
|
addrNonceKey := ms.dstoreKey(addr)
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
_, err = buf.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, nonce))
|
_, err := buf.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, nonce))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, xerrors.Errorf("failed to marshall nonce: %w", err)
|
return xerrors.Errorf("failed to marshall nonce: %w", err)
|
||||||
}
|
}
|
||||||
err = ms.ds.Put(addrNonceKey, buf.Bytes())
|
err = ms.ds.Put(addrNonceKey, buf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, xerrors.Errorf("failed to write nonce to datastore: %w", err)
|
return xerrors.Errorf("failed to write nonce to datastore: %w", err)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
return nonce, nil
|
}
|
||||||
|
|
||||||
|
func (ms *MessageSigner) dstoreKey(addr address.Address) datastore.Key {
|
||||||
|
return datastore.KeyWithNamespaces([]string{dsKeyActorNonce, addr.String()})
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
"github.com/filecoin-project/lotus/chain/wallet"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
@ -58,6 +60,7 @@ func TestMessageSignerSignMessage(t *testing.T) {
|
|||||||
msg *types.Message
|
msg *types.Message
|
||||||
mpoolNonce [1]uint64
|
mpoolNonce [1]uint64
|
||||||
expNonce uint64
|
expNonce uint64
|
||||||
|
cbErr error
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@ -137,6 +140,37 @@ func TestMessageSignerSignMessage(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expNonce: 2,
|
expNonce: 2,
|
||||||
}},
|
}},
|
||||||
|
}, {
|
||||||
|
name: "recover from callback error",
|
||||||
|
msgs: []msgSpec{{
|
||||||
|
// No nonce yet in datastore
|
||||||
|
msg: &types.Message{
|
||||||
|
To: to1,
|
||||||
|
From: from1,
|
||||||
|
},
|
||||||
|
expNonce: 0,
|
||||||
|
}, {
|
||||||
|
// Increment nonce
|
||||||
|
msg: &types.Message{
|
||||||
|
To: to1,
|
||||||
|
From: from1,
|
||||||
|
},
|
||||||
|
expNonce: 1,
|
||||||
|
}, {
|
||||||
|
// Callback returns error
|
||||||
|
msg: &types.Message{
|
||||||
|
To: to1,
|
||||||
|
From: from1,
|
||||||
|
},
|
||||||
|
cbErr: xerrors.Errorf("err"),
|
||||||
|
}, {
|
||||||
|
// Callback successful, should increment nonce in datastore
|
||||||
|
msg: &types.Message{
|
||||||
|
To: to1,
|
||||||
|
From: from1,
|
||||||
|
},
|
||||||
|
expNonce: 2,
|
||||||
|
}},
|
||||||
}}
|
}}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
tt := tt
|
tt := tt
|
||||||
@ -149,9 +183,18 @@ func TestMessageSignerSignMessage(t *testing.T) {
|
|||||||
if len(m.mpoolNonce) == 1 {
|
if len(m.mpoolNonce) == 1 {
|
||||||
mpool.setNonce(m.msg.From, m.mpoolNonce[0])
|
mpool.setNonce(m.msg.From, m.mpoolNonce[0])
|
||||||
}
|
}
|
||||||
smsg, err := ms.SignMessage(ctx, m.msg)
|
merr := m.cbErr
|
||||||
require.NoError(t, err)
|
smsg, err := ms.SignMessage(ctx, m.msg, func(message *types.SignedMessage) error {
|
||||||
require.Equal(t, m.expNonce, smsg.Message.Nonce)
|
return merr
|
||||||
|
})
|
||||||
|
|
||||||
|
if m.cbErr != nil {
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Nil(t, smsg)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, m.expNonce, smsg.Message.Nonce)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,8 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"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"
|
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ var log = logging.Logger("statetree")
|
|||||||
// StateTree stores actors state by their ID.
|
// StateTree stores actors state by their ID.
|
||||||
type StateTree struct {
|
type StateTree struct {
|
||||||
root adt.Map
|
root adt.Map
|
||||||
version builtin.Version // TODO
|
version types.StateTreeVersion
|
||||||
info cid.Cid
|
info cid.Cid
|
||||||
Store cbor.IpldStore
|
Store cbor.IpldStore
|
||||||
|
|
||||||
@ -120,15 +121,41 @@ func (ss *stateSnaps) deleteActor(addr address.Address) {
|
|||||||
ss.layers[len(ss.layers)-1].actors[addr] = streeOp{Delete: true}
|
ss.layers[len(ss.layers)-1].actors[addr] = streeOp{Delete: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateTree(cst cbor.IpldStore, version builtin.Version) (*StateTree, error) {
|
// VersionForNetwork returns the state tree version for the given network
|
||||||
var info cid.Cid
|
// version.
|
||||||
switch version {
|
func VersionForNetwork(ver network.Version) types.StateTreeVersion {
|
||||||
case builtin.Version0:
|
if actors.VersionForNetwork(ver) == actors.Version0 {
|
||||||
// info is undefined
|
return types.StateTreeVersion0
|
||||||
default:
|
|
||||||
return nil, xerrors.Errorf("unsupported state tree version: %d", version)
|
|
||||||
}
|
}
|
||||||
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), version)
|
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 ver {
|
||||||
|
case types.StateTreeVersion0:
|
||||||
|
// info is undefined
|
||||||
|
case types.StateTreeVersion1:
|
||||||
|
var err error
|
||||||
|
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", ver)
|
||||||
|
}
|
||||||
|
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), adtForSTVersion(ver))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -136,7 +163,7 @@ func NewStateTree(cst cbor.IpldStore, version builtin.Version) (*StateTree, erro
|
|||||||
return &StateTree{
|
return &StateTree{
|
||||||
root: root,
|
root: root,
|
||||||
info: info,
|
info: info,
|
||||||
version: version,
|
version: ver,
|
||||||
Store: cst,
|
Store: cst,
|
||||||
snaps: newStateSnaps(),
|
snaps: newStateSnaps(),
|
||||||
}, nil
|
}, nil
|
||||||
@ -148,30 +175,31 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
|
|||||||
if err := cst.Get(context.TODO(), c, &root); err != nil {
|
if err := cst.Get(context.TODO(), c, &root); err != nil {
|
||||||
// We failed to decode as the new version, must be an old version.
|
// We failed to decode as the new version, must be an old version.
|
||||||
root.Actors = c
|
root.Actors = c
|
||||||
root.Version = builtin.Version0
|
root.Version = types.StateTreeVersion0
|
||||||
}
|
|
||||||
|
|
||||||
// If that fails, load as an old-style state-tree (direct hampt, version 0.
|
|
||||||
nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), root.Actors, builtin.Version(root.Version))
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("loading hamt node %s failed: %s", c, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch root.Version {
|
switch root.Version {
|
||||||
case builtin.Version0:
|
case types.StateTreeVersion0, types.StateTreeVersion1:
|
||||||
// supported
|
// Load the actual state-tree HAMT.
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
return &StateTree{
|
||||||
|
root: nd,
|
||||||
|
info: root.Info,
|
||||||
|
version: root.Version,
|
||||||
|
Store: cst,
|
||||||
|
snaps: newStateSnaps(),
|
||||||
|
}, nil
|
||||||
default:
|
default:
|
||||||
return nil, xerrors.Errorf("unsupported state tree version: %d", root.Version)
|
return nil, xerrors.Errorf("unsupported state tree version: %d", root.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &StateTree{
|
|
||||||
root: nd,
|
|
||||||
info: root.Info,
|
|
||||||
version: builtin.Version(root.Version),
|
|
||||||
Store: cst,
|
|
||||||
snaps: newStateSnaps(),
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error {
|
func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error {
|
||||||
@ -305,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)
|
return cid.Undef, xerrors.Errorf("failed to flush state-tree hamt: %w", err)
|
||||||
}
|
}
|
||||||
// If we're version 0, return a raw tree.
|
// If we're version 0, return a raw tree.
|
||||||
if st.version == builtin.Version0 {
|
if st.version == types.StateTreeVersion0 {
|
||||||
return root, nil
|
return root, nil
|
||||||
}
|
}
|
||||||
// Otherwise, return a versioned tree.
|
// 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 {
|
func (st *StateTree) Snapshot(ctx context.Context) error {
|
||||||
@ -396,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.
|
// Version returns the version of the StateTree data structure in use.
|
||||||
func (st *StateTree) Version() builtin.Version {
|
func (st *StateTree) Version() types.StateTreeVersion {
|
||||||
return st.version
|
return st.version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,16 +9,16 @@ import (
|
|||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
|
||||||
address "github.com/filecoin-project/go-address"
|
address "github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
builtin2 "github.com/filecoin-project/lotus/chain/actors/builtin"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkStateTreeSet(b *testing.B) {
|
func BenchmarkStateTreeSet(b *testing.B) {
|
||||||
cst := cbor.NewMemCborStore()
|
cst := cbor.NewMemCborStore()
|
||||||
st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion))
|
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ func BenchmarkStateTreeSet(b *testing.B) {
|
|||||||
|
|
||||||
func BenchmarkStateTreeSetFlush(b *testing.B) {
|
func BenchmarkStateTreeSetFlush(b *testing.B) {
|
||||||
cst := cbor.NewMemCborStore()
|
cst := cbor.NewMemCborStore()
|
||||||
st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion))
|
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) {
|
|||||||
|
|
||||||
func BenchmarkStateTree10kGetActor(b *testing.B) {
|
func BenchmarkStateTree10kGetActor(b *testing.B) {
|
||||||
cst := cbor.NewMemCborStore()
|
cst := cbor.NewMemCborStore()
|
||||||
st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion))
|
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) {
|
|||||||
|
|
||||||
func TestSetCache(t *testing.T) {
|
func TestSetCache(t *testing.T) {
|
||||||
cst := cbor.NewMemCborStore()
|
cst := cbor.NewMemCborStore()
|
||||||
st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion))
|
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -154,7 +154,7 @@ func TestSetCache(t *testing.T) {
|
|||||||
func TestSnapshots(t *testing.T) {
|
func TestSnapshots(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
cst := cbor.NewMemCborStore()
|
cst := cbor.NewMemCborStore()
|
||||||
st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion))
|
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -237,7 +237,8 @@ func assertNotHas(t *testing.T, st *StateTree, addr address.Address) {
|
|||||||
|
|
||||||
func TestStateTreeConsistency(t *testing.T) {
|
func TestStateTreeConsistency(t *testing.T) {
|
||||||
cst := cbor.NewMemCborStore()
|
cst := cbor.NewMemCborStore()
|
||||||
st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion))
|
// TODO: ActorUpgrade: this test tests pre actors v2
|
||||||
|
st, err := NewStateTree(cst, VersionForNetwork(network.Version3))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,10 @@ package stmgr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"go.opencensus.io/trace"
|
"go.opencensus.io/trace"
|
||||||
@ -18,14 +18,47 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate cid.Cid, r vm.Rand, bheight abi.ChainEpoch) (*api.InvocResult, error) {
|
var ErrExpensiveFork = errors.New("refusing explicit call due to state fork at epoch")
|
||||||
ctx, span := trace.StartSpan(ctx, "statemanager.CallRaw")
|
|
||||||
|
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()
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
vmopt := &vm.VMOpts{
|
vmopt := &vm.VMOpts{
|
||||||
StateBase: bstate,
|
StateBase: bstate,
|
||||||
Epoch: bheight,
|
Epoch: bheight,
|
||||||
Rand: r,
|
Rand: store.NewChainRand(sm.cs, ts.Cids()),
|
||||||
Bstore: sm.cs.Blockstore(),
|
Bstore: sm.cs.Blockstore(),
|
||||||
Syscalls: sm.cs.VMSys(),
|
Syscalls: sm.cs.VMSys(),
|
||||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||||
@ -33,7 +66,7 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
|
|||||||
BaseFee: types.NewInt(0),
|
BaseFee: types.NewInt(0),
|
||||||
}
|
}
|
||||||
|
|
||||||
vmi, err := vm.NewVM(ctx, vmopt)
|
vmi, err := sm.newVM(ctx, vmopt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
||||||
}
|
}
|
||||||
@ -89,24 +122,30 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) {
|
|
||||||
if ts == nil {
|
|
||||||
ts = sm.cs.GetHeaviestTipSet()
|
|
||||||
}
|
|
||||||
|
|
||||||
state := ts.ParentState()
|
|
||||||
|
|
||||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
|
||||||
|
|
||||||
return sm.CallRaw(ctx, msg, state, r, ts.Height())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, priorMsgs []types.ChainMsg, ts *types.TipSet) (*api.InvocResult, error) {
|
func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, priorMsgs []types.ChainMsg, ts *types.TipSet) (*api.InvocResult, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "statemanager.CallWithGas")
|
ctx, span := trace.StartSpan(ctx, "statemanager.CallWithGas")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
if ts == nil {
|
if ts == nil {
|
||||||
ts = sm.cs.GetHeaviestTipSet()
|
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)
|
state, _, err := sm.TipSetState(ctx, ts)
|
||||||
@ -114,6 +153,11 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
|||||||
return nil, xerrors.Errorf("computing tipset state: %w", err)
|
return nil, xerrors.Errorf("computing tipset state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state, err = sm.handleStateForks(ctx, state, ts.Height(), nil, ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to handle fork: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
r := store.NewChainRand(sm.cs, ts.Cids())
|
||||||
|
|
||||||
if span.IsRecordingEvents() {
|
if span.IsRecordingEvents() {
|
||||||
@ -134,7 +178,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
|||||||
NtwkVersion: sm.GetNtwkVersion,
|
NtwkVersion: sm.GetNtwkVersion,
|
||||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||||
}
|
}
|
||||||
vmi, err := vm.NewVM(ctx, vmopt)
|
vmi, err := sm.newVM(ctx, vmopt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -6,45 +6,153 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/migration/nv3"
|
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
|
multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/migration/nv3"
|
||||||
|
m2 "github.com/filecoin-project/specs-actors/v2/actors/migration"
|
||||||
|
states2 "github.com/filecoin-project/specs-actors/v2/actors/states"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"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/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||||
"golang.org/x/xerrors"
|
"github.com/filecoin-project/lotus/lib/bufbstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ForksAtHeight = map[abi.ChainEpoch]func(context.Context, *StateManager, ExecCallback, cid.Cid, *types.TipSet) (cid.Cid, error){
|
// UpgradeFunc is a migration function run at every upgrade.
|
||||||
build.UpgradeBreezeHeight: UpgradeFaucetBurnRecovery,
|
//
|
||||||
build.UpgradeIgnitionHeight: UpgradeIgnition,
|
// - The oldState is the state produced by the upgrade epoch.
|
||||||
build.UpgradeLiftoffHeight: UpgradeLiftoff,
|
// - 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
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpgradeSchedule []Upgrade
|
||||||
|
|
||||||
|
func DefaultUpgradeSchedule() UpgradeSchedule {
|
||||||
|
var us UpgradeSchedule
|
||||||
|
|
||||||
|
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.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
|
||||||
|
}
|
||||||
|
us = append(us, u)
|
||||||
|
}
|
||||||
|
return us
|
||||||
|
}
|
||||||
|
|
||||||
|
func (us UpgradeSchedule) Validate() error {
|
||||||
|
// Make sure we're not trying to upgrade to version 0.
|
||||||
|
for _, u := range us {
|
||||||
|
if u.Network <= 0 {
|
||||||
|
return xerrors.Errorf("cannot upgrade to version <= 0: %d", u.Network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure all the upgrades make sense.
|
||||||
|
for i := 1; i < len(us); i++ {
|
||||||
|
prev := &us[i-1]
|
||||||
|
curr := &us[i]
|
||||||
|
if !(prev.Network <= curr.Network) {
|
||||||
|
return xerrors.Errorf("cannot downgrade from version %d to version %d", prev.Network, curr.Network)
|
||||||
|
}
|
||||||
|
// Make sure the heights make sense.
|
||||||
|
if prev.Height < 0 {
|
||||||
|
// Previous upgrade was disabled.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !(prev.Height < curr.Height) {
|
||||||
|
return xerrors.Errorf("upgrade heights must be strictly increasing: upgrade %d was at height %d, followed by upgrade %d at height %d", i-1, prev.Height, i, curr.Height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, height abi.ChainEpoch, cb ExecCallback, ts *types.TipSet) (cid.Cid, error) {
|
func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, height abi.ChainEpoch, cb ExecCallback, ts *types.TipSet) (cid.Cid, error) {
|
||||||
retCid := root
|
retCid := root
|
||||||
var err error
|
var err error
|
||||||
f, ok := ForksAtHeight[height]
|
f, ok := sm.stateMigrations[height]
|
||||||
if ok {
|
if ok {
|
||||||
retCid, err = f(ctx, sm, cb, root, ts)
|
retCid, err = f(ctx, sm, cb, root, height, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
@ -53,6 +161,11 @@ func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, heig
|
|||||||
return retCid, nil
|
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 {
|
func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address, amt abi.TokenAmount) error {
|
||||||
fromAct, err := tree.GetActor(from)
|
fromAct, err := tree.GetActor(from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -115,7 +228,7 @@ func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address,
|
|||||||
return nil
|
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
|
// Some initial parameters
|
||||||
FundsForMiners := types.FromFil(1_000_000)
|
FundsForMiners := types.FromFil(1_000_000)
|
||||||
LookbackEpoch := abi.ChainEpoch(32000)
|
LookbackEpoch := abi.ChainEpoch(32000)
|
||||||
@ -367,10 +480,14 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
|||||||
return tree.Flush(ctx)
|
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)
|
store := sm.cs.Store(ctx)
|
||||||
|
|
||||||
nst, err := nv3.MigrateStateTree(ctx, store, root, build.UpgradeIgnitionHeight)
|
if build.UpgradeLiftoffHeight <= epoch {
|
||||||
|
return cid.Undef, xerrors.Errorf("liftoff height must be beyond ignition height")
|
||||||
|
}
|
||||||
|
|
||||||
|
nst, err := nv3.MigrateStateTree(ctx, store, root, epoch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("migrating actors state: %w", err)
|
return cid.Undef, xerrors.Errorf("migrating actors state: %w", err)
|
||||||
}
|
}
|
||||||
@ -395,7 +512,7 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
|||||||
return cid.Undef, xerrors.Errorf("second split address: %w", err)
|
return cid.Undef, xerrors.Errorf("second split address: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = resetGenesisMsigs(ctx, sm, store, tree)
|
err = resetGenesisMsigs(ctx, sm, store, tree, build.UpgradeLiftoffHeight)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("resetting genesis msig start epochs: %w", err)
|
return cid.Undef, xerrors.Errorf("resetting genesis msig start epochs: %w", err)
|
||||||
}
|
}
|
||||||
@ -410,7 +527,7 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
|||||||
return cid.Undef, xerrors.Errorf("splitting second msig: %w", err)
|
return cid.Undef, xerrors.Errorf("splitting second msig: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = nv3.CheckStateTree(ctx, store, nst, build.UpgradeIgnitionHeight, builtin0.TotalFilecoin)
|
err = nv3.CheckStateTree(ctx, store, nst, epoch, builtin0.TotalFilecoin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("sanity check after ignition upgrade failed: %w", err)
|
return cid.Undef, xerrors.Errorf("sanity check after ignition upgrade failed: %w", err)
|
||||||
}
|
}
|
||||||
@ -418,7 +535,97 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
|||||||
return tree.Flush(ctx)
|
return tree.Flush(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeLiftoff(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := address.NewFromString("t0122")
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("getting address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
newHamtRoot, err := m2.MigrateStateTree(ctx, store, root, epoch, m2.DefaultConfig())
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("upgrading to actors v2: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newStateTree, err := states2.LoadTree(store, newHamtRoot)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("failed to load new state tree: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check all state-tree invariants.
|
||||||
|
if msgs, err := states2.CheckStateInvariants(newStateTree, types.TotalFilecoinInt); err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("failed to check new state tree: %w", err)
|
||||||
|
} else if !msgs.IsEmpty() {
|
||||||
|
// This error is going to be really nasty.
|
||||||
|
return cid.Undef, xerrors.Errorf("network upgrade failed: %v", msgs.Messages())
|
||||||
|
}
|
||||||
|
|
||||||
|
newRoot, err := store.Put(ctx, &types.StateRoot{
|
||||||
|
Version: types.StateTreeVersion1,
|
||||||
|
Actors: newHamtRoot,
|
||||||
|
Info: info,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("failed to persist new state root: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform some basic sanity checks to make sure everything still works.
|
||||||
|
if newSm, err := state.LoadStateTree(store, newRoot); err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("state tree sanity load failed: %w", err)
|
||||||
|
} else if newRoot2, err := newSm.Flush(ctx); err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("state tree sanity flush failed: %w", err)
|
||||||
|
} else if newRoot2 != newRoot {
|
||||||
|
return cid.Undef, xerrors.Errorf("state-root mismatch: %s != %s", newRoot, newRoot2)
|
||||||
|
} else if _, err := newSm.GetActor(builtin0.InitActorAddr); err != nil {
|
||||||
|
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, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
tree, err := sm.StateTree(root)
|
tree, err := sm.StateTree(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||||
@ -432,20 +639,22 @@ func UpgradeLiftoff(ctx context.Context, sm *StateManager, cb ExecCallback, root
|
|||||||
return tree.Flush(ctx)
|
return tree.Flush(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setNetworkName(ctx context.Context, store adt0.Store, tree *state.StateTree, name string) error {
|
func setNetworkName(ctx context.Context, store adt.Store, tree *state.StateTree, name string) error {
|
||||||
ia, err := tree.GetActor(builtin0.InitActorAddr)
|
ia, err := tree.GetActor(builtin0.InitActorAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("getting init actor: %w", err)
|
return xerrors.Errorf("getting init actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var initState init0.State
|
initState, err := init_.Load(store, ia)
|
||||||
if err := store.Get(ctx, ia.Head, &initState); err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("reading init state: %w", err)
|
return xerrors.Errorf("reading init state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
initState.NetworkName = name
|
if err := initState.SetNetworkName(name); err != nil {
|
||||||
|
return xerrors.Errorf("setting network name: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
ia.Head, err = store.Put(ctx, &initState)
|
ia.Head, err = store.Put(ctx, initState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("writing new init state: %w", err)
|
return xerrors.Errorf("writing new init state: %w", err)
|
||||||
}
|
}
|
||||||
@ -574,7 +783,8 @@ func makeKeyAddr(splitAddr address.Address, count uint64) (address.Address, erro
|
|||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store, tree *state.StateTree) error {
|
// 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()
|
gb, err := sm.cs.GetGenesis()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("getting genesis block: %w", err)
|
return xerrors.Errorf("getting genesis block: %w", err)
|
||||||
@ -603,7 +813,7 @@ func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store,
|
|||||||
return xerrors.Errorf("reading multisig state: %w", err)
|
return xerrors.Errorf("reading multisig state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
currState.StartEpoch = build.UpgradeLiftoffHeight
|
currState.StartEpoch = startEpoch
|
||||||
|
|
||||||
currActor.Head, err = store.Put(ctx, &currState)
|
currActor.Head, err = store.Put(ctx, &currState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -623,3 +833,34 @@ func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store,
|
|||||||
|
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
@ -8,9 +8,11 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"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/filecoin-project/specs-actors/actors/runtime"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
@ -18,7 +20,6 @@ import (
|
|||||||
lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
"github.com/filecoin-project/lotus/chain/gen"
|
"github.com/filecoin-project/lotus/chain/gen"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
|
||||||
. "github.com/filecoin-project/lotus/chain/stmgr"
|
. "github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
@ -26,7 +27,7 @@ import (
|
|||||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
ipldcbor "github.com/ipfs/go-ipld-cbor"
|
||||||
logging "github.com/ipfs/go-log"
|
logging "github.com/ipfs/go-log"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
)
|
)
|
||||||
@ -42,6 +43,10 @@ const testForkHeight = 40
|
|||||||
type testActor struct {
|
type testActor struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// must use existing actor that an account is allowed to exec.
|
||||||
|
func (testActor) Code() cid.Cid { return builtin.PaymentChannelActorCodeID }
|
||||||
|
func (testActor) State() cbor.Er { return new(testActorState) }
|
||||||
|
|
||||||
type testActorState struct {
|
type testActorState struct {
|
||||||
HasUpgraded uint64
|
HasUpgraded uint64
|
||||||
}
|
}
|
||||||
@ -62,7 +67,7 @@ func (tas *testActorState) UnmarshalCBOR(r io.Reader) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ta *testActor) Exports() []interface{} {
|
func (ta testActor) Exports() []interface{} {
|
||||||
return []interface{}{
|
return []interface{}{
|
||||||
1: ta.Constructor,
|
1: ta.Constructor,
|
||||||
2: ta.TestMethod,
|
2: ta.TestMethod,
|
||||||
@ -72,7 +77,7 @@ func (ta *testActor) Exports() []interface{} {
|
|||||||
func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue {
|
func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue {
|
||||||
rt.ValidateImmediateCallerAcceptAny()
|
rt.ValidateImmediateCallerAcceptAny()
|
||||||
rt.StateCreate(&testActorState{11})
|
rt.StateCreate(&testActorState{11})
|
||||||
fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
|
//fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
|
||||||
|
|
||||||
return abi.Empty
|
return abi.Empty
|
||||||
}
|
}
|
||||||
@ -105,51 +110,57 @@ func TestForkHeightTriggers(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sm := NewStateManager(cg.ChainStore())
|
|
||||||
|
|
||||||
inv := vm.NewInvoker()
|
|
||||||
|
|
||||||
// predicting the address here... may break if other assumptions change
|
// predicting the address here... may break if other assumptions change
|
||||||
taddr, err := address.NewIDAddress(1002)
|
taddr, err := address.NewIDAddress(1002)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stmgr.ForksAtHeight[testForkHeight] = func(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
sm, err := NewStateManagerWithUpgradeSchedule(
|
||||||
cst := cbor.NewCborStore(sm.ChainStore().Blockstore())
|
cg.ChainStore(), UpgradeSchedule{{
|
||||||
|
Network: 1,
|
||||||
|
Height: testForkHeight,
|
||||||
|
Migration: func(ctx context.Context, sm *StateManager, cb ExecCallback,
|
||||||
|
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
|
cst := ipldcbor.NewCborStore(sm.ChainStore().Blockstore())
|
||||||
|
|
||||||
st, err := sm.StateTree(root)
|
st, err := sm.StateTree(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
act, err := st.GetActor(taddr)
|
act, err := st.GetActor(taddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var tas testActorState
|
var tas testActorState
|
||||||
if err := cst.Get(ctx, act.Head, &tas); err != nil {
|
if err := cst.Get(ctx, act.Head, &tas); err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("in fork handler, failed to run get: %w", err)
|
return cid.Undef, xerrors.Errorf("in fork handler, failed to run get: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tas.HasUpgraded = 55
|
tas.HasUpgraded = 55
|
||||||
|
|
||||||
ns, err := cst.Put(ctx, &tas)
|
ns, err := cst.Put(ctx, &tas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
act.Head = ns
|
act.Head = ns
|
||||||
|
|
||||||
if err := st.SetActor(taddr, act); err != nil {
|
if err := st.SetActor(taddr, act); err != nil {
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return st.Flush(ctx)
|
return st.Flush(ctx)
|
||||||
|
}}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
inv.Register(builtin.PaymentChannelActorCodeID, &testActor{}, &testActorState{})
|
inv := vm.NewActorRegistry()
|
||||||
|
inv.Register(nil, testActor{})
|
||||||
|
|
||||||
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
|
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
|
||||||
nvm, err := vm.NewVM(ctx, vmopt)
|
nvm, err := vm.NewVM(ctx, vmopt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -163,7 +174,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
|||||||
|
|
||||||
var msgs []*types.SignedMessage
|
var msgs []*types.SignedMessage
|
||||||
|
|
||||||
enc, err := actors.SerializeParams(&init_.ExecParams{CodeCID: builtin.PaymentChannelActorCodeID})
|
enc, err := actors.SerializeParams(&init0.ExecParams{CodeCID: (testActor{}).Code()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -223,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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||||
|
|
||||||
@ -24,7 +26,6 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
||||||
@ -38,9 +39,25 @@ import (
|
|||||||
|
|
||||||
var log = logging.Logger("statemgr")
|
var log = logging.Logger("statemgr")
|
||||||
|
|
||||||
|
type versionSpec struct {
|
||||||
|
networkVersion network.Version
|
||||||
|
atOrBelow abi.ChainEpoch
|
||||||
|
}
|
||||||
|
|
||||||
type StateManager struct {
|
type StateManager struct {
|
||||||
cs *store.ChainStore
|
cs *store.ChainStore
|
||||||
|
|
||||||
|
// Determines the network version at any given epoch.
|
||||||
|
networkVersions []versionSpec
|
||||||
|
latestVersion network.Version
|
||||||
|
|
||||||
|
// 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
|
stCache map[string][]cid.Cid
|
||||||
compWait map[string]chan struct{}
|
compWait map[string]chan struct{}
|
||||||
stlk sync.Mutex
|
stlk sync.Mutex
|
||||||
@ -51,12 +68,54 @@ type StateManager struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewStateManager(cs *store.ChainStore) *StateManager {
|
func NewStateManager(cs *store.ChainStore) *StateManager {
|
||||||
return &StateManager{
|
sm, err := NewStateManagerWithUpgradeSchedule(cs, DefaultUpgradeSchedule())
|
||||||
newVM: vm.NewVM,
|
if err != nil {
|
||||||
cs: cs,
|
panic(fmt.Sprintf("default upgrade schedule is invalid: %s", err))
|
||||||
stCache: make(map[string][]cid.Cid),
|
|
||||||
compWait: make(map[string]chan struct{}),
|
|
||||||
}
|
}
|
||||||
|
return sm
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule) (*StateManager, error) {
|
||||||
|
// If we have upgrades, make sure they're in-order and make sense.
|
||||||
|
if err := us.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
// If we have any upgrades, process them and create a version
|
||||||
|
// schedule.
|
||||||
|
for _, upgrade := range us {
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
lastVersion = upgrade.Network
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Otherwise, go directly to the latest version.
|
||||||
|
lastVersion = build.NewestNetworkVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
return &StateManager{
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func cidsToKey(cids []cid.Cid) string {
|
func cidsToKey(cids []cid.Cid) string {
|
||||||
@ -279,7 +338,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
|||||||
|
|
||||||
sysAct, actErr := vmi.StateTree().GetActor(builtin0.SystemActorAddr)
|
sysAct, actErr := vmi.StateTree().GetActor(builtin0.SystemActorAddr)
|
||||||
if actErr != nil {
|
if actErr != nil {
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to get system actor: %w", err)
|
return cid.Undef, cid.Undef, xerrors.Errorf("failed to get system actor: %w", actErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
rwMsg := &types.Message{
|
rwMsg := &types.Message{
|
||||||
@ -295,7 +354,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
|||||||
}
|
}
|
||||||
ret, actErr := vmi.ApplyImplicitMessage(ctx, rwMsg)
|
ret, actErr := vmi.ApplyImplicitMessage(ctx, rwMsg)
|
||||||
if actErr != nil {
|
if actErr != nil {
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, err)
|
return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, actErr)
|
||||||
}
|
}
|
||||||
if cb != nil {
|
if cb != nil {
|
||||||
if err := cb(rwMsg.Cid(), rwMsg, ret); err != nil {
|
if err := cb(rwMsg.Cid(), rwMsg, ret); err != nil {
|
||||||
@ -313,7 +372,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// XXX: Is the height correct? Or should it be epoch-1?
|
// XXX: Is the height correct? Or should it be epoch-1?
|
||||||
rectarr, err := adt.NewArray(sm.cs.Store(ctx), builtin.VersionForNetwork(sm.GetNtwkVersion(ctx, epoch)))
|
rectarr, err := adt.NewArray(sm.cs.Store(ctx), actors.VersionForNetwork(sm.GetNtwkVersion(ctx, epoch)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to create receipts amt: %w", err)
|
return cid.Undef, cid.Undef, xerrors.Errorf("failed to create receipts amt: %w", err)
|
||||||
}
|
}
|
||||||
@ -859,7 +918,7 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
|
|||||||
|
|
||||||
totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount)
|
totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount)
|
||||||
err = sTree.ForEach(func(kaddr address.Address, act *types.Actor) error {
|
err = sTree.ForEach(func(kaddr address.Address, act *types.Actor) error {
|
||||||
if act.IsMultisigActor() {
|
if builtin.IsMultisigActor(act.Code) {
|
||||||
s, err := multisig.Load(sm.cs.Store(ctx), act)
|
s, err := multisig.Load(sm.cs.Store(ctx), act)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -891,7 +950,7 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
|
|||||||
totalsByEpoch[ud] = ib
|
totalsByEpoch[ud] = ib
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if act.IsAccountActor() {
|
} else if builtin.IsAccountActor(act.Code) {
|
||||||
// should exclude burnt funds actor and "remainder account actor"
|
// should exclude burnt funds actor and "remainder account actor"
|
||||||
// should only ever be "faucet" accounts in testnets
|
// should only ever be "faucet" accounts in testnets
|
||||||
if kaddr == builtin0.BurntFundsActorAddr {
|
if kaddr == builtin0.BurntFundsActorAddr {
|
||||||
@ -1121,14 +1180,27 @@ func (sm *StateManager) GetFilVested(ctx context.Context, height abi.ChainEpoch,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// continue to use preIgnitionGenInfos, nothing changed at the Ignition epoch
|
// After UpgradeActorsV2Height these funds are accounted for in GetFilReserveDisbursed
|
||||||
vf = big.Add(vf, sm.preIgnitionGenInfos.genesisPledge)
|
if height <= build.UpgradeActorsV2Height {
|
||||||
// continue to use preIgnitionGenInfos, nothing changed at the Ignition epoch
|
// continue to use preIgnitionGenInfos, nothing changed at the Ignition epoch
|
||||||
vf = big.Add(vf, sm.preIgnitionGenInfos.genesisMarketFunds)
|
vf = big.Add(vf, sm.preIgnitionGenInfos.genesisPledge)
|
||||||
|
// continue to use preIgnitionGenInfos, nothing changed at the Ignition epoch
|
||||||
|
vf = big.Add(vf, sm.preIgnitionGenInfos.genesisMarketFunds)
|
||||||
|
}
|
||||||
|
|
||||||
return vf, nil
|
return vf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetFilReserveDisbursed(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) {
|
||||||
|
ract, err := st.GetActor(builtin.ReserveAddress)
|
||||||
|
if err != nil {
|
||||||
|
return big.Zero(), xerrors.Errorf("failed to get reserve actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If money enters the reserve actor, this could lead to a negative term
|
||||||
|
return big.Sub(big.NewFromGo(build.InitialFilReserved), ract.Balance), nil
|
||||||
|
}
|
||||||
|
|
||||||
func GetFilMined(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) {
|
func GetFilMined(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) {
|
||||||
ractor, err := st.GetActor(reward.Address)
|
ractor, err := st.GetActor(reward.Address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1216,6 +1288,14 @@ func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height
|
|||||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filVested: %w", err)
|
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filVested: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filReserveDisbursed := big.Zero()
|
||||||
|
if height > build.UpgradeActorsV2Height {
|
||||||
|
filReserveDisbursed, err = GetFilReserveDisbursed(ctx, st)
|
||||||
|
if err != nil {
|
||||||
|
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filReserveDisbursed: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
filMined, err := GetFilMined(ctx, st)
|
filMined, err := GetFilMined(ctx, st)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filMined: %w", err)
|
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filMined: %w", err)
|
||||||
@ -1232,6 +1312,7 @@ func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret := types.BigAdd(filVested, filMined)
|
ret := types.BigAdd(filVested, filMined)
|
||||||
|
ret = types.BigAdd(ret, filReserveDisbursed)
|
||||||
ret = types.BigSub(ret, filBurnt)
|
ret = types.BigSub(ret, filBurnt)
|
||||||
ret = types.BigSub(ret, filLocked)
|
ret = types.BigSub(ret, filLocked)
|
||||||
|
|
||||||
@ -1258,25 +1339,14 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version {
|
func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version {
|
||||||
// TODO: move hard fork epoch checks to a schedule defined in build/
|
// The epochs here are the _last_ epoch for every version, or -1 if the
|
||||||
|
// version is disabled.
|
||||||
if build.UseNewestNetwork() {
|
for _, spec := range sm.networkVersions {
|
||||||
return build.NewestNetworkVersion
|
if height <= spec.atOrBelow {
|
||||||
|
return spec.networkVersion
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return sm.latestVersion
|
||||||
if height <= build.UpgradeBreezeHeight {
|
|
||||||
return network.Version0
|
|
||||||
}
|
|
||||||
|
|
||||||
if height <= build.UpgradeSmokeHeight {
|
|
||||||
return network.Version1
|
|
||||||
}
|
|
||||||
|
|
||||||
if height <= build.UpgradeIgnitionHeight {
|
|
||||||
return network.Version2
|
|
||||||
}
|
|
||||||
|
|
||||||
return build.NewestNetworkVersion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) {
|
func (sm *StateManager) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) {
|
||||||
|
@ -9,6 +9,11 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
|
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
@ -17,22 +22,14 @@ import (
|
|||||||
"github.com/filecoin-project/go-bitfield"
|
"github.com/filecoin-project/go-bitfield"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
|
"github.com/filecoin-project/go-state-types/rt"
|
||||||
|
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
account0 "github.com/filecoin-project/specs-actors/actors/builtin/account"
|
exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
||||||
cron0 "github.com/filecoin-project/specs-actors/actors/builtin/cron"
|
|
||||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
|
||||||
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
|
||||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
|
||||||
paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
||||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
|
||||||
reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
|
||||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
|
||||||
proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||||
|
exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
|
||||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||||
@ -390,7 +387,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
|||||||
NtwkVersion: sm.GetNtwkVersion,
|
NtwkVersion: sm.GetNtwkVersion,
|
||||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||||
}
|
}
|
||||||
vmi, err := vm.NewVM(ctx, vmopt)
|
vmi, err := sm.newVM(ctx, vmopt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, nil, err
|
return cid.Undef, nil, err
|
||||||
}
|
}
|
||||||
@ -416,8 +413,9 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
|||||||
|
|
||||||
func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types.TipSet, round abi.ChainEpoch) (*types.TipSet, error) {
|
func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types.TipSet, round abi.ChainEpoch) (*types.TipSet, error) {
|
||||||
var lbr abi.ChainEpoch
|
var lbr abi.ChainEpoch
|
||||||
if round > build.WinningPoStSectorSetLookback {
|
lb := policy.GetWinningPoStSectorSetLookback(sm.GetNtwkVersion(ctx, round))
|
||||||
lbr = round - build.WinningPoStSectorSetLookback
|
if round > lb {
|
||||||
|
lbr = round - lb
|
||||||
}
|
}
|
||||||
|
|
||||||
// more null blocks than our lookback
|
// more null blocks than our lookback
|
||||||
@ -497,7 +495,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
mpow, tpow, hmp, err := GetPowerRaw(ctx, sm, lbst, maddr)
|
mpow, tpow, _, err := GetPowerRaw(ctx, sm, lbst, maddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to get power: %w", err)
|
return nil, xerrors.Errorf("failed to get power: %w", err)
|
||||||
}
|
}
|
||||||
@ -512,15 +510,21 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule
|
|||||||
return nil, xerrors.Errorf("resolving worker address: %w", err)
|
return nil, xerrors.Errorf("resolving worker address: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Not ideal performance...This method reloads miner and power state (already looked up here and in GetPowerRaw)
|
||||||
|
eligible, err := MinerEligibleToMine(ctx, sm, maddr, ts, lbts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("determining miner eligibility: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &api.MiningBaseInfo{
|
return &api.MiningBaseInfo{
|
||||||
MinerPower: mpow.QualityAdjPower,
|
MinerPower: mpow.QualityAdjPower,
|
||||||
NetworkPower: tpow.QualityAdjPower,
|
NetworkPower: tpow.QualityAdjPower,
|
||||||
Sectors: sectors,
|
Sectors: sectors,
|
||||||
WorkerKey: worker,
|
WorkerKey: worker,
|
||||||
SectorSize: info.SectorSize,
|
SectorSize: info.SectorSize,
|
||||||
PrevBeaconEntry: *prev,
|
PrevBeaconEntry: *prev,
|
||||||
BeaconEntries: entries,
|
BeaconEntries: entries,
|
||||||
HasMinPower: hmp,
|
EligibleForMining: eligible,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,42 +538,23 @@ type MethodMeta struct {
|
|||||||
var MethodsMap = map[cid.Cid]map[abi.MethodNum]MethodMeta{}
|
var MethodsMap = map[cid.Cid]map[abi.MethodNum]MethodMeta{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cidToMethods := map[cid.Cid][2]interface{}{
|
// TODO: combine with the runtime actor registry.
|
||||||
// builtin.SystemActorCodeID: {builtin.MethodsSystem, system.Actor{} }- apparently it doesn't have methods
|
var actors []rt.VMActor
|
||||||
builtin0.InitActorCodeID: {builtin0.MethodsInit, init0.Actor{}},
|
actors = append(actors, exported0.BuiltinActors()...)
|
||||||
builtin0.CronActorCodeID: {builtin0.MethodsCron, cron0.Actor{}},
|
actors = append(actors, exported2.BuiltinActors()...)
|
||||||
builtin0.AccountActorCodeID: {builtin0.MethodsAccount, account0.Actor{}},
|
|
||||||
builtin0.StoragePowerActorCodeID: {builtin0.MethodsPower, power0.Actor{}},
|
|
||||||
builtin0.StorageMinerActorCodeID: {builtin0.MethodsMiner, miner0.Actor{}},
|
|
||||||
builtin0.StorageMarketActorCodeID: {builtin0.MethodsMarket, market0.Actor{}},
|
|
||||||
builtin0.PaymentChannelActorCodeID: {builtin0.MethodsPaych, paych0.Actor{}},
|
|
||||||
builtin0.MultisigActorCodeID: {builtin0.MethodsMultisig, msig0.Actor{}},
|
|
||||||
builtin0.RewardActorCodeID: {builtin0.MethodsReward, reward0.Actor{}},
|
|
||||||
builtin0.VerifiedRegistryActorCodeID: {builtin0.MethodsVerifiedRegistry, verifreg0.Actor{}},
|
|
||||||
}
|
|
||||||
|
|
||||||
for c, m := range cidToMethods {
|
for _, actor := range actors {
|
||||||
exports := m[1].(vm.Invokee).Exports()
|
exports := actor.Exports()
|
||||||
methods := make(map[abi.MethodNum]MethodMeta, len(exports))
|
methods := make(map[abi.MethodNum]MethodMeta, len(exports))
|
||||||
|
|
||||||
// Explicitly add send, it's special.
|
// Explicitly add send, it's special.
|
||||||
|
// Note that builtin2.MethodSend = builtin0.MethodSend = 0.
|
||||||
methods[builtin0.MethodSend] = MethodMeta{
|
methods[builtin0.MethodSend] = MethodMeta{
|
||||||
Name: "Send",
|
Name: "Send",
|
||||||
Params: reflect.TypeOf(new(abi.EmptyValue)),
|
Params: reflect.TypeOf(new(abi.EmptyValue)),
|
||||||
Ret: reflect.TypeOf(new(abi.EmptyValue)),
|
Ret: reflect.TypeOf(new(abi.EmptyValue)),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Learn method names from the builtin.Methods* structs.
|
|
||||||
rv := reflect.ValueOf(m[0])
|
|
||||||
rt := rv.Type()
|
|
||||||
nf := rt.NumField()
|
|
||||||
methodToName := make([]string, len(exports))
|
|
||||||
for i := 0; i < nf; i++ {
|
|
||||||
name := rt.Field(i).Name
|
|
||||||
number := rv.Field(i).Interface().(abi.MethodNum)
|
|
||||||
methodToName[number] = name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate over exported methods. Some of these _may_ be nil and
|
// Iterate over exported methods. Some of these _may_ be nil and
|
||||||
// must be skipped.
|
// must be skipped.
|
||||||
for number, export := range exports {
|
for number, export := range exports {
|
||||||
@ -580,22 +565,19 @@ func init() {
|
|||||||
ev := reflect.ValueOf(export)
|
ev := reflect.ValueOf(export)
|
||||||
et := ev.Type()
|
et := ev.Type()
|
||||||
|
|
||||||
// Make sure the method name is correct.
|
// Extract the method names using reflection. These
|
||||||
// This is just a nice sanity check.
|
// method names always match the field names in the
|
||||||
|
// `builtin.Method*` structs (tested in the specs-actors
|
||||||
|
// tests).
|
||||||
fnName := runtime.FuncForPC(ev.Pointer()).Name()
|
fnName := runtime.FuncForPC(ev.Pointer()).Name()
|
||||||
fnName = strings.TrimSuffix(fnName[strings.LastIndexByte(fnName, '.')+1:], "-fm")
|
fnName = strings.TrimSuffix(fnName[strings.LastIndexByte(fnName, '.')+1:], "-fm")
|
||||||
mName := methodToName[number]
|
|
||||||
if mName != fnName {
|
|
||||||
panic(fmt.Sprintf(
|
|
||||||
"actor method name is %s but exported method name is %s",
|
|
||||||
fnName, mName,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
switch abi.MethodNum(number) {
|
switch abi.MethodNum(number) {
|
||||||
case builtin0.MethodSend:
|
case builtin0.MethodSend:
|
||||||
|
// Note that builtin2.MethodSend = builtin0.MethodSend = 0.
|
||||||
panic("method 0 is reserved for Send")
|
panic("method 0 is reserved for Send")
|
||||||
case builtin0.MethodConstructor:
|
case builtin0.MethodConstructor:
|
||||||
|
// Note that builtin2.MethodConstructor = builtin0.MethodConstructor = 1.
|
||||||
if fnName != "Constructor" {
|
if fnName != "Constructor" {
|
||||||
panic("method 1 is reserved for Constructor")
|
panic("method 1 is reserved for Constructor")
|
||||||
}
|
}
|
||||||
@ -607,7 +589,7 @@ func init() {
|
|||||||
Ret: et.Out(0),
|
Ret: et.Out(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MethodsMap[c] = methods
|
MethodsMap[actor.Code()] = methods
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -624,7 +606,7 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me
|
|||||||
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func MinerHasMinPower(ctx context.Context, sm *StateManager, addr address.Address, ts *types.TipSet) (bool, error) {
|
func minerHasMinPower(ctx context.Context, sm *StateManager, addr address.Address, ts *types.TipSet) (bool, error) {
|
||||||
pact, err := sm.LoadActor(ctx, power.Address, ts)
|
pact, err := sm.LoadActor(ctx, power.Address, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, xerrors.Errorf("loading power actor state: %w", err)
|
return false, xerrors.Errorf("loading power actor state: %w", err)
|
||||||
@ -638,6 +620,70 @@ func MinerHasMinPower(ctx context.Context, sm *StateManager, addr address.Addres
|
|||||||
return ps.MinerNominalPowerMeetsConsensusMinimum(addr)
|
return ps.MinerNominalPowerMeetsConsensusMinimum(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MinerEligibleToMine(ctx context.Context, sm *StateManager, addr address.Address, baseTs *types.TipSet, lookbackTs *types.TipSet) (bool, error) {
|
||||||
|
hmp, err := minerHasMinPower(ctx, sm, addr, lookbackTs)
|
||||||
|
|
||||||
|
// TODO: We're blurring the lines between a "runtime network version" and a "Lotus upgrade epoch", is that unavoidable?
|
||||||
|
if sm.GetNtwkVersion(ctx, baseTs.Height()) <= network.Version3 {
|
||||||
|
return hmp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hmp {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post actors v2, also check MinerEligibleForElection with base ts
|
||||||
|
|
||||||
|
pact, err := sm.LoadActor(ctx, power.Address, baseTs)
|
||||||
|
if err != nil {
|
||||||
|
return false, xerrors.Errorf("loading power actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pstate, err := power.Load(sm.cs.Store(ctx), pact)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mact, err := sm.LoadActor(ctx, addr, baseTs)
|
||||||
|
if err != nil {
|
||||||
|
return false, xerrors.Errorf("loading miner actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mstate, err := miner.Load(sm.cs.Store(ctx), mact)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-empty power claim.
|
||||||
|
if claim, found, err := pstate.MinerPower(addr); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else if !found {
|
||||||
|
return false, err
|
||||||
|
} else if claim.QualityAdjPower.LessThanEqual(big.Zero()) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// No fee debt.
|
||||||
|
if debt, err := mstate.FeeDebt(); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else if !debt.IsZero() {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// No active consensus faults.
|
||||||
|
if mInfo, err := mstate.Info(); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else if baseTs.Height() <= mInfo.ConsensusFaultElapsed {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
func CheckTotalFIL(ctx context.Context, sm *StateManager, ts *types.TipSet) (abi.TokenAmount, error) {
|
func CheckTotalFIL(ctx context.Context, sm *StateManager, ts *types.TipSet) (abi.TokenAmount, error) {
|
||||||
str, err := state.LoadStateTree(sm.ChainStore().Store(ctx), ts.ParentState())
|
str, err := state.LoadStateTree(sm.ChainStore().Store(ctx), ts.ParentState())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -46,7 +46,7 @@ func ComputeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi.TokenAmount, error) {
|
func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi.TokenAmount, error) {
|
||||||
if ts.Height() > build.UpgradeBreezeHeight && ts.Height() < build.UpgradeBreezeHeight+build.BreezeGasTampingDuration {
|
if build.UpgradeBreezeHeight >= 0 && ts.Height() > build.UpgradeBreezeHeight && ts.Height() < build.UpgradeBreezeHeight+build.BreezeGasTampingDuration {
|
||||||
return abi.NewTokenAmount(100), nil
|
return abi.NewTokenAmount(100), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,24 +11,27 @@ import (
|
|||||||
|
|
||||||
func TestBaseFee(t *testing.T) {
|
func TestBaseFee(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
basefee uint64
|
basefee uint64
|
||||||
limitUsed int64
|
limitUsed int64
|
||||||
noOfBlocks int
|
noOfBlocks int
|
||||||
output uint64
|
preSmoke, postSmoke uint64
|
||||||
}{
|
}{
|
||||||
{100e6, 0, 1, 87.5e6},
|
{100e6, 0, 1, 87.5e6, 87.5e6},
|
||||||
{100e6, 0, 5, 87.5e6},
|
{100e6, 0, 5, 87.5e6, 87.5e6},
|
||||||
{100e6, build.BlockGasTarget, 1, 103.125e6},
|
{100e6, build.BlockGasTarget, 1, 103.125e6, 100e6},
|
||||||
{100e6, build.BlockGasTarget * 2, 2, 103.125e6},
|
{100e6, build.BlockGasTarget * 2, 2, 103.125e6, 100e6},
|
||||||
{100e6, build.BlockGasLimit * 2, 2, 112.5e6},
|
{100e6, build.BlockGasLimit * 2, 2, 112.5e6, 112.5e6},
|
||||||
{100e6, build.BlockGasLimit * 1.5, 2, 110937500},
|
{100e6, build.BlockGasLimit * 1.5, 2, 110937500, 106.250e6},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
test := test
|
test := test
|
||||||
t.Run(fmt.Sprintf("%v", test), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%v", test), func(t *testing.T) {
|
||||||
output := ComputeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks, 0)
|
preSmoke := ComputeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks, build.UpgradeSmokeHeight-1)
|
||||||
assert.Equal(t, fmt.Sprintf("%d", test.output), output.String())
|
assert.Equal(t, fmt.Sprintf("%d", test.preSmoke), preSmoke.String())
|
||||||
|
|
||||||
|
postSmoke := ComputeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks, build.UpgradeSmokeHeight+1)
|
||||||
|
assert.Equal(t, fmt.Sprintf("%d", test.postSmoke), postSmoke.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,13 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
"github.com/filecoin-project/lotus/journal"
|
"github.com/filecoin-project/lotus/journal"
|
||||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||||
@ -757,7 +759,8 @@ func (cs *ChainStore) GetSignedMessage(c cid.Cid) (*types.SignedMessage, error)
|
|||||||
|
|
||||||
func (cs *ChainStore) readAMTCids(root cid.Cid) ([]cid.Cid, error) {
|
func (cs *ChainStore) readAMTCids(root cid.Cid) ([]cid.Cid, error) {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
a, err := adt.AsArray(cs.Store(ctx), root)
|
// block headers use adt0, for now.
|
||||||
|
a, err := adt0.AsArray(cs.Store(ctx), root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("amt load: %w", err)
|
return nil, xerrors.Errorf("amt load: %w", err)
|
||||||
}
|
}
|
||||||
@ -950,7 +953,8 @@ func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message,
|
|||||||
|
|
||||||
func (cs *ChainStore) GetParentReceipt(b *types.BlockHeader, i int) (*types.MessageReceipt, error) {
|
func (cs *ChainStore) GetParentReceipt(b *types.BlockHeader, i int) (*types.MessageReceipt, error) {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
a, err := adt.AsArray(cs.Store(ctx), b.ParentMessageReceipts)
|
// block headers use adt0, for now.
|
||||||
|
a, err := adt0.AsArray(cs.Store(ctx), b.ParentMessageReceipts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("amt load: %w", err)
|
return nil, xerrors.Errorf("amt load: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
address "github.com/filecoin-project/go-address"
|
address "github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
blocks "github.com/ipfs/go-block-format"
|
blocks "github.com/ipfs/go-block-format"
|
||||||
bserv "github.com/ipfs/go-blockservice"
|
bserv "github.com/ipfs/go-blockservice"
|
||||||
@ -24,6 +23,8 @@ import (
|
|||||||
"go.opencensus.io/stats"
|
"go.opencensus.io/stats"
|
||||||
"go.opencensus.io/tag"
|
"go.opencensus.io/tag"
|
||||||
|
|
||||||
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain"
|
"github.com/filecoin-project/lotus/chain"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||||
@ -43,7 +44,11 @@ var log = logging.Logger("sub")
|
|||||||
var ErrSoftFailure = errors.New("soft validation failure")
|
var ErrSoftFailure = errors.New("soft validation failure")
|
||||||
var ErrInsufficientPower = errors.New("incoming block's miner does not have minimum power")
|
var ErrInsufficientPower = errors.New("incoming block's miner does not have minimum power")
|
||||||
|
|
||||||
func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *chain.Syncer, bserv bserv.BlockService, cmgr connmgr.ConnManager) {
|
func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *chain.Syncer, bs bserv.BlockService, cmgr connmgr.ConnManager) {
|
||||||
|
// Timeout after (block time + propagation delay). This is useless at
|
||||||
|
// this point.
|
||||||
|
timeout := time.Duration(build.BlockDelaySecs+build.PropagationDelaySecs) * time.Second
|
||||||
|
|
||||||
for {
|
for {
|
||||||
msg, err := bsub.Next(ctx)
|
msg, err := bsub.Next(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -64,15 +69,22 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
|
|||||||
src := msg.GetFrom()
|
src := msg.GetFrom()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// NOTE: we could also share a single session between
|
||||||
|
// all requests but that may have other consequences.
|
||||||
|
ses := bserv.NewSession(ctx, bs)
|
||||||
|
|
||||||
start := build.Clock.Now()
|
start := build.Clock.Now()
|
||||||
log.Debug("about to fetch messages for block from pubsub")
|
log.Debug("about to fetch messages for block from pubsub")
|
||||||
bmsgs, err := FetchMessagesByCids(context.TODO(), bserv, blk.BlsMessages)
|
bmsgs, err := FetchMessagesByCids(ctx, ses, blk.BlsMessages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to fetch all bls messages for block received over pubusb: %s; source: %s", err, src)
|
log.Errorf("failed to fetch all bls messages for block received over pubusb: %s; source: %s", err, src)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
smsgs, err := FetchSignedMessagesByCids(context.TODO(), bserv, blk.SecpkMessages)
|
smsgs, err := FetchSignedMessagesByCids(ctx, ses, blk.SecpkMessages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to fetch all secpk messages for block received over pubusb: %s; source: %s", err, src)
|
log.Errorf("failed to fetch all secpk messages for block received over pubusb: %s; source: %s", err, src)
|
||||||
return
|
return
|
||||||
@ -97,7 +109,7 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
|
|||||||
|
|
||||||
func FetchMessagesByCids(
|
func FetchMessagesByCids(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
bserv bserv.BlockService,
|
bserv bserv.BlockGetter,
|
||||||
cids []cid.Cid,
|
cids []cid.Cid,
|
||||||
) ([]*types.Message, error) {
|
) ([]*types.Message, error) {
|
||||||
out := make([]*types.Message, len(cids))
|
out := make([]*types.Message, len(cids))
|
||||||
@ -126,7 +138,7 @@ func FetchMessagesByCids(
|
|||||||
// FIXME: Duplicate of above.
|
// FIXME: Duplicate of above.
|
||||||
func FetchSignedMessagesByCids(
|
func FetchSignedMessagesByCids(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
bserv bserv.BlockService,
|
bserv bserv.BlockGetter,
|
||||||
cids []cid.Cid,
|
cids []cid.Cid,
|
||||||
) ([]*types.SignedMessage, error) {
|
) ([]*types.SignedMessage, error) {
|
||||||
out := make([]*types.SignedMessage, len(cids))
|
out := make([]*types.SignedMessage, len(cids))
|
||||||
@ -156,12 +168,11 @@ func FetchSignedMessagesByCids(
|
|||||||
// blocks we did not request.
|
// blocks we did not request.
|
||||||
func fetchCids(
|
func fetchCids(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
bserv bserv.BlockService,
|
bserv bserv.BlockGetter,
|
||||||
cids []cid.Cid,
|
cids []cid.Cid,
|
||||||
cb func(int, blocks.Block) error,
|
cb func(int, blocks.Block) error,
|
||||||
) error {
|
) error {
|
||||||
// FIXME: Why don't we use the context here?
|
fetchedBlocks := bserv.GetBlocks(ctx, cids)
|
||||||
fetchedBlocks := bserv.GetBlocks(context.TODO(), cids)
|
|
||||||
|
|
||||||
cidIndex := make(map[cid.Cid]int)
|
cidIndex := make(map[cid.Cid]int)
|
||||||
for i, c := range cids {
|
for i, c := range cids {
|
||||||
@ -374,9 +385,10 @@ func (bv *BlockValidator) isChainNearSynced() bool {
|
|||||||
|
|
||||||
func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error {
|
func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error {
|
||||||
// TODO there has to be a simpler way to do this without the blockstore dance
|
// TODO there has to be a simpler way to do this without the blockstore dance
|
||||||
store := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewTemporary()))
|
// block headers use adt0
|
||||||
bmArr := adt.MakeEmptyArray(store)
|
store := adt0.WrapStore(ctx, cbor.NewCborStore(blockstore.NewTemporary()))
|
||||||
smArr := adt.MakeEmptyArray(store)
|
bmArr := adt0.MakeEmptyArray(store)
|
||||||
|
smArr := adt0.MakeEmptyArray(store)
|
||||||
|
|
||||||
for i, m := range msg.BlsMessages {
|
for i, m := range msg.BlsMessages {
|
||||||
c := cbg.CborCid(m)
|
c := cbg.CborCid(m)
|
||||||
@ -473,14 +485,14 @@ func (bv *BlockValidator) checkPowerAndGetWorkerKey(ctx context.Context, bh *typ
|
|||||||
return address.Undef, ErrSoftFailure
|
return address.Undef, ErrSoftFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
hmp, err := stmgr.MinerHasMinPower(ctx, bv.stmgr, bh.Miner, lbts)
|
eligible, err := stmgr.MinerEligibleToMine(ctx, bv.stmgr, bh.Miner, baseTs, lbts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("failed to determine if incoming block's miner has minimum power: %s", err)
|
log.Warnf("failed to determine if incoming block's miner has minimum power: %s", err)
|
||||||
return address.Undef, ErrSoftFailure
|
return address.Undef, ErrSoftFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hmp {
|
if !eligible {
|
||||||
log.Warnf("incoming block's miner does not have minimum power")
|
log.Warnf("incoming block's miner is ineligible")
|
||||||
return address.Undef, ErrInsufficientPower
|
return address.Undef, ErrInsufficientPower
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||||
@ -33,9 +35,10 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
||||||
blst "github.com/supranational/blst/bindings/go"
|
blst "github.com/supranational/blst/bindings/go"
|
||||||
|
|
||||||
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||||
@ -455,9 +458,10 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types
|
|||||||
// computeMsgMeta computes the root CID of the combined arrays of message CIDs
|
// computeMsgMeta computes the root CID of the combined arrays of message CIDs
|
||||||
// of both types (BLS and Secpk).
|
// of both types (BLS and Secpk).
|
||||||
func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cid.Cid) (cid.Cid, error) {
|
func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cid.Cid) (cid.Cid, error) {
|
||||||
store := adt.WrapStore(context.TODO(), bs)
|
// block headers use adt0
|
||||||
bmArr := adt.MakeEmptyArray(store)
|
store := adt0.WrapStore(context.TODO(), bs)
|
||||||
smArr := adt.MakeEmptyArray(store)
|
bmArr := adt0.MakeEmptyArray(store)
|
||||||
|
smArr := adt0.MakeEmptyArray(store)
|
||||||
|
|
||||||
for i, m := range bmsgCids {
|
for i, m := range bmsgCids {
|
||||||
c := cbg.CborCid(m)
|
c := cbg.CborCid(m)
|
||||||
@ -823,13 +827,13 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock, use
|
|||||||
return xerrors.Errorf("block is not claiming to be a winner")
|
return xerrors.Errorf("block is not claiming to be a winner")
|
||||||
}
|
}
|
||||||
|
|
||||||
hp, err := stmgr.MinerHasMinPower(ctx, syncer.sm, h.Miner, lbts)
|
eligible, err := stmgr.MinerEligibleToMine(ctx, syncer.sm, h.Miner, baseTs, lbts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("determining if miner has min power failed: %w", err)
|
return xerrors.Errorf("determining if miner has min power failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hp {
|
if !eligible {
|
||||||
return xerrors.New("block's miner does not meet minimum power threshold")
|
return xerrors.New("block's miner is ineligible to mine")
|
||||||
}
|
}
|
||||||
|
|
||||||
rBeacon := *prevBeacon
|
rBeacon := *prevBeacon
|
||||||
@ -1087,7 +1091,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
|||||||
return xerrors.Errorf("failed to get actor: %w", err)
|
return xerrors.Errorf("failed to get actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !act.IsAccountActor() {
|
if !builtin.IsAccountActor(act.Code) {
|
||||||
return xerrors.New("Sender must be an account actor")
|
return xerrors.New("Sender must be an account actor")
|
||||||
}
|
}
|
||||||
nonces[m.From] = act.Nonce
|
nonces[m.From] = act.Nonce
|
||||||
@ -1101,9 +1105,9 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
store := adt.WrapStore(ctx, cst)
|
store := adt0.WrapStore(ctx, cst)
|
||||||
|
|
||||||
bmArr := adt.MakeEmptyArray(store)
|
bmArr := adt0.MakeEmptyArray(store)
|
||||||
for i, m := range b.BlsMessages {
|
for i, m := range b.BlsMessages {
|
||||||
if err := checkMsg(m); err != nil {
|
if err := checkMsg(m); err != nil {
|
||||||
return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
|
return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
|
||||||
@ -1115,7 +1119,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
smArr := adt.MakeEmptyArray(store)
|
smArr := adt0.MakeEmptyArray(store)
|
||||||
for i, m := range b.SecpkMessages {
|
for i, m := range b.SecpkMessages {
|
||||||
if err := checkMsg(m); err != nil {
|
if err := checkMsg(m); err != nil {
|
||||||
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
|
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
|
||||||
|
@ -4,8 +4,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrActorNotFound = errors.New("actor not found")
|
var ErrActorNotFound = errors.New("actor not found")
|
||||||
@ -17,19 +15,3 @@ type Actor struct {
|
|||||||
Nonce uint64
|
Nonce uint64
|
||||||
Balance BigInt
|
Balance BigInt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Actor) IsAccountActor() bool {
|
|
||||||
return a.Code == builtin0.AccountActorCodeID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Actor) IsStorageMinerActor() bool {
|
|
||||||
return a.Code == builtin0.StorageMinerActorCodeID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Actor) IsMultisigActor() bool {
|
|
||||||
return a.Code == builtin0.MultisigActorCodeID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Actor) IsPaymentChannelActor() bool {
|
|
||||||
return a.Code == builtin0.PaymentChannelActorCodeID
|
|
||||||
}
|
|
||||||
|
@ -1648,7 +1648,7 @@ func (t *StateRoot) MarshalCBOR(w io.Writer) error {
|
|||||||
|
|
||||||
scratch := make([]byte, 9)
|
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 {
|
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Version)); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1687,7 +1687,7 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
|
|||||||
return fmt.Errorf("cbor input had wrong number of fields")
|
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 {
|
if maj != cbg.MajUnsignedInt {
|
||||||
return fmt.Errorf("wrong type for uint64 field")
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
}
|
}
|
||||||
t.Version = uint64(extra)
|
t.Version = StateTreeVersion(extra)
|
||||||
|
|
||||||
}
|
}
|
||||||
// t.Actors (cid.Cid) (struct)
|
// t.Actors (cid.Cid) (struct)
|
||||||
@ -1728,22 +1728,22 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
|
|||||||
return nil
|
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 {
|
if t == nil {
|
||||||
_, err := w.Write(cbg.CborNull)
|
_, err := w.Write(cbg.CborNull)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := w.Write(lengthBufStateInfo); err != nil {
|
if _, err := w.Write(lengthBufStateInfo0); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *StateInfo) UnmarshalCBOR(r io.Reader) error {
|
func (t *StateInfo0) UnmarshalCBOR(r io.Reader) error {
|
||||||
*t = StateInfo{}
|
*t = StateInfo0{}
|
||||||
|
|
||||||
br := cbg.GetPeeker(r)
|
br := cbg.GetPeeker(r)
|
||||||
scratch := make([]byte, 8)
|
scratch := make([]byte, 8)
|
||||||
|
@ -2,9 +2,20 @@ package types
|
|||||||
|
|
||||||
import "github.com/ipfs/go-cid"
|
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 {
|
type StateRoot struct {
|
||||||
// State root version. Versioned along with actors (for now).
|
// State tree version.
|
||||||
Version uint64
|
Version StateTreeVersion
|
||||||
// Actors tree. The structure depends on the state root version.
|
// Actors tree. The structure depends on the state root version.
|
||||||
Actors cid.Cid
|
Actors cid.Cid
|
||||||
// Info. The structure depends on the state root version.
|
// Info. The structure depends on the state root version.
|
||||||
@ -12,4 +23,4 @@ type StateRoot struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: version this.
|
// TODO: version this.
|
||||||
type StateInfo struct{}
|
type StateInfo0 struct{}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
)
|
|
||||||
|
|
||||||
func DecodeSignedVoucher(s string) (*paych.SignedVoucher, error) {
|
|
||||||
data, err := base64.RawURLEncoding.DecodeString(s)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var sv paych.SignedVoucher
|
|
||||||
if err := cbor.DecodeInto(data, &sv); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &sv, nil
|
|
||||||
}
|
|
@ -6,28 +6,25 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"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/go-state-types/crypto"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
"github.com/filecoin-project/lotus/chain/gen"
|
"github.com/filecoin-project/lotus/chain/gen"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||||
"github.com/filecoin-project/lotus/chain/vectors"
|
"github.com/filecoin-project/lotus/chain/vectors"
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
"github.com/filecoin-project/lotus/chain/wallet"
|
||||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
|
||||||
|
|
||||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
verifreg0.MinVerifiedDealSize = big.NewInt(2048)
|
policy.SetMinVerifiedDealSize(abi.NewStoragePower(2048))
|
||||||
power0.ConsensusMinerMinPower = big.NewInt(2048)
|
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeHeaderVectors() []vectors.HeaderVector {
|
func MakeHeaderVectors() []vectors.HeaderVector {
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
addr "github.com/filecoin-project/go-address"
|
addr "github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
|
||||||
vmr "github.com/filecoin-project/specs-actors/actors/runtime"
|
vmr "github.com/filecoin-project/specs-actors/actors/runtime"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
)
|
)
|
||||||
@ -210,7 +209,7 @@ func (ps pricedSyscalls) VerifyPoSt(vi proof.WindowPoStVerifyInfo) error {
|
|||||||
// the "parent grinding fault", in which case it must be the sibling of h1 (same parent tipset) and one of the
|
// the "parent grinding fault", in which case it must be the sibling of h1 (same parent tipset) and one of the
|
||||||
// blocks in the parent of h2 (i.e. h2's grandparent).
|
// blocks in the parent of h2 (i.e. h2's grandparent).
|
||||||
// Returns nil and an error if the headers don't prove a fault.
|
// Returns nil and an error if the headers don't prove a fault.
|
||||||
func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte) (*runtime.ConsensusFault, error) {
|
func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte) (*vmr.ConsensusFault, error) {
|
||||||
ps.chargeGas(ps.pl.OnVerifyConsensusFault())
|
ps.chargeGas(ps.pl.OnVerifyConsensusFault())
|
||||||
defer ps.chargeGas(gasOnActorExec)
|
defer ps.chargeGas(gasOnActorExec)
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
type scalingCost struct {
|
type scalingCost struct {
|
||||||
@ -112,14 +112,14 @@ func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.M
|
|||||||
|
|
||||||
if big.Cmp(value, abi.NewTokenAmount(0)) != 0 {
|
if big.Cmp(value, abi.NewTokenAmount(0)) != 0 {
|
||||||
ret += pl.sendTransferFunds
|
ret += pl.sendTransferFunds
|
||||||
if methodNum == builtin.MethodSend {
|
if methodNum == builtin0.MethodSend {
|
||||||
// transfer only
|
// transfer only
|
||||||
ret += pl.sendTransferOnlyPremium
|
ret += pl.sendTransferOnlyPremium
|
||||||
}
|
}
|
||||||
extra += "t"
|
extra += "t"
|
||||||
}
|
}
|
||||||
|
|
||||||
if methodNum != builtin.MethodSend {
|
if methodNum != builtin0.MethodSend {
|
||||||
extra += "i"
|
extra += "i"
|
||||||
// running actors is cheaper becase we hand over to actors
|
// running actors is cheaper becase we hand over to actors
|
||||||
ret += pl.sendInvokeMethod
|
ret += pl.sendInvokeMethod
|
||||||
|
@ -6,91 +6,126 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
||||||
account0 "github.com/filecoin-project/specs-actors/actors/builtin/account"
|
exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported"
|
||||||
cron0 "github.com/filecoin-project/specs-actors/actors/builtin/cron"
|
vmr "github.com/filecoin-project/specs-actors/v2/actors/runtime"
|
||||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
|
||||||
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
|
||||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
|
||||||
paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
||||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
|
||||||
reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
|
||||||
system0 "github.com/filecoin-project/specs-actors/actors/builtin/system"
|
|
||||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
|
||||||
vmr "github.com/filecoin-project/specs-actors/actors/runtime"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/exitcode"
|
"github.com/filecoin-project/go-state-types/exitcode"
|
||||||
|
rtt "github.com/filecoin-project/go-state-types/rt"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Invoker struct {
|
type ActorRegistry struct {
|
||||||
builtInCode map[cid.Cid]nativeCode
|
actors map[cid.Cid]*actorInfo
|
||||||
builtInState map[cid.Cid]reflect.Type
|
}
|
||||||
|
|
||||||
|
// An ActorPredicate returns an error if the given actor is not valid for the given runtime environment (e.g., chain height, version, etc.).
|
||||||
|
type ActorPredicate func(vmr.Runtime, rtt.VMActor) error
|
||||||
|
|
||||||
|
func ActorsVersionPredicate(ver actors.Version) ActorPredicate {
|
||||||
|
return func(rt vmr.Runtime, v rtt.VMActor) error {
|
||||||
|
nver := actors.VersionForNetwork(rt.NetworkVersion())
|
||||||
|
if nver != ver {
|
||||||
|
return xerrors.Errorf("actor %s is a version %d actor; chain only supports actor version %d at height %d", v.Code(), ver, nver, rt.CurrEpoch())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type invokeFunc func(rt vmr.Runtime, params []byte) ([]byte, aerrors.ActorError)
|
type invokeFunc func(rt vmr.Runtime, params []byte) ([]byte, aerrors.ActorError)
|
||||||
type nativeCode []invokeFunc
|
type nativeCode []invokeFunc
|
||||||
|
|
||||||
func NewInvoker() *Invoker {
|
type actorInfo struct {
|
||||||
inv := &Invoker{
|
methods nativeCode
|
||||||
builtInCode: make(map[cid.Cid]nativeCode),
|
vmActor rtt.VMActor
|
||||||
builtInState: make(map[cid.Cid]reflect.Type),
|
// TODO: consider making this a network version range?
|
||||||
}
|
predicate ActorPredicate
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewActorRegistry() *ActorRegistry {
|
||||||
|
inv := &ActorRegistry{actors: make(map[cid.Cid]*actorInfo)}
|
||||||
|
|
||||||
|
// TODO: define all these properties on the actors themselves, in specs-actors.
|
||||||
|
|
||||||
// add builtInCode using: register(cid, singleton)
|
// add builtInCode using: register(cid, singleton)
|
||||||
// NETUPGRADE: register code IDs for v2, etc.
|
inv.Register(ActorsVersionPredicate(actors.Version0), exported0.BuiltinActors()...)
|
||||||
inv.Register(builtin0.SystemActorCodeID, system0.Actor{}, abi.EmptyValue{})
|
inv.Register(ActorsVersionPredicate(actors.Version2), exported2.BuiltinActors()...)
|
||||||
inv.Register(builtin0.InitActorCodeID, init0.Actor{}, init0.State{})
|
|
||||||
inv.Register(builtin0.RewardActorCodeID, reward0.Actor{}, reward0.State{})
|
|
||||||
inv.Register(builtin0.CronActorCodeID, cron0.Actor{}, cron0.State{})
|
|
||||||
inv.Register(builtin0.StoragePowerActorCodeID, power0.Actor{}, power0.State{})
|
|
||||||
inv.Register(builtin0.StorageMarketActorCodeID, market0.Actor{}, market0.State{})
|
|
||||||
inv.Register(builtin0.StorageMinerActorCodeID, miner0.Actor{}, miner0.State{})
|
|
||||||
inv.Register(builtin0.MultisigActorCodeID, msig0.Actor{}, msig0.State{})
|
|
||||||
inv.Register(builtin0.PaymentChannelActorCodeID, paych0.Actor{}, paych0.State{})
|
|
||||||
inv.Register(builtin0.VerifiedRegistryActorCodeID, verifreg0.Actor{}, verifreg0.State{})
|
|
||||||
inv.Register(builtin0.AccountActorCodeID, account0.Actor{}, account0.State{})
|
|
||||||
|
|
||||||
return inv
|
return inv
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inv *Invoker) Invoke(codeCid cid.Cid, rt vmr.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) {
|
func (ar *ActorRegistry) Invoke(codeCid cid.Cid, rt vmr.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) {
|
||||||
|
act, ok := ar.actors[codeCid]
|
||||||
code, ok := inv.builtInCode[codeCid]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("no code for actor %s (Addr: %s)", codeCid, rt.Receiver())
|
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))
|
return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "no code for actor %s(%d)(%s)", codeCid, method, hex.EncodeToString(params))
|
||||||
}
|
}
|
||||||
if method >= abi.MethodNum(len(code)) || code[method] == nil {
|
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)
|
return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "no method %d on actor", method)
|
||||||
}
|
}
|
||||||
return code[method](rt, params)
|
return act.methods[method](rt, params)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inv *Invoker) Register(c cid.Cid, instance Invokee, state interface{}) {
|
func (ar *ActorRegistry) Register(pred ActorPredicate, actors ...rtt.VMActor) {
|
||||||
code, err := inv.transform(instance)
|
if pred == nil {
|
||||||
if err != nil {
|
pred = func(vmr.Runtime, rtt.VMActor) error { return nil }
|
||||||
panic(xerrors.Errorf("%s: %w", string(c.Hash()), err))
|
}
|
||||||
|
for _, a := range actors {
|
||||||
|
code, err := ar.transform(a)
|
||||||
|
if err != nil {
|
||||||
|
panic(xerrors.Errorf("%s: %w", string(a.Code().Hash()), err))
|
||||||
|
}
|
||||||
|
ar.actors[a.Code()] = &actorInfo{
|
||||||
|
methods: code,
|
||||||
|
vmActor: a,
|
||||||
|
predicate: pred,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
inv.builtInCode[c] = code
|
|
||||||
inv.builtInState[c] = reflect.TypeOf(state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Invokee interface {
|
func (ar *ActorRegistry) Create(codeCid cid.Cid, rt vmr.Runtime) (*types.Actor, aerrors.ActorError) {
|
||||||
|
act, ok := ar.actors[codeCid]
|
||||||
|
if !ok {
|
||||||
|
return nil, aerrors.Newf(exitcode.SysErrorIllegalArgument, "Can only create built-in actors.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := act.predicate(rt, act.vmActor); err != nil {
|
||||||
|
return nil, aerrors.Newf(exitcode.SysErrorIllegalArgument, "Cannot create actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rtt.IsSingletonActor(act.vmActor) {
|
||||||
|
return nil, aerrors.Newf(exitcode.SysErrorIllegalArgument, "Can only have one instance of singleton actors.")
|
||||||
|
}
|
||||||
|
return &types.Actor{
|
||||||
|
Code: codeCid,
|
||||||
|
Head: EmptyObjectCid,
|
||||||
|
Nonce: 0,
|
||||||
|
Balance: abi.NewTokenAmount(0),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type invokee interface {
|
||||||
Exports() []interface{}
|
Exports() []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Invoker) transform(instance Invokee) (nativeCode, error) {
|
func (*ActorRegistry) transform(instance invokee) (nativeCode, error) {
|
||||||
itype := reflect.TypeOf(instance)
|
itype := reflect.TypeOf(instance)
|
||||||
exports := instance.Exports()
|
exports := instance.Exports()
|
||||||
|
runtimeType := reflect.TypeOf((*vmr.Runtime)(nil)).Elem()
|
||||||
for i, m := range exports {
|
for i, m := range exports {
|
||||||
i := i
|
i := i
|
||||||
newErr := func(format string, args ...interface{}) error {
|
newErr := func(format string, args ...interface{}) error {
|
||||||
@ -111,7 +146,7 @@ func (*Invoker) transform(instance Invokee) (nativeCode, error) {
|
|||||||
return nil, newErr("wrong number of inputs should be: " +
|
return nil, newErr("wrong number of inputs should be: " +
|
||||||
"vmr.Runtime, <parameter>")
|
"vmr.Runtime, <parameter>")
|
||||||
}
|
}
|
||||||
if t.In(0) != reflect.TypeOf((*vmr.Runtime)(nil)).Elem() {
|
if !runtimeType.Implements(t.In(0)) {
|
||||||
return nil, newErr("first arguemnt should be vmr.Runtime")
|
return nil, newErr("first arguemnt should be vmr.Runtime")
|
||||||
}
|
}
|
||||||
if t.In(1).Kind() != reflect.Ptr {
|
if t.In(1).Kind() != reflect.Ptr {
|
||||||
@ -176,27 +211,22 @@ func DecodeParams(b []byte, out interface{}) error {
|
|||||||
return um.UnmarshalCBOR(bytes.NewReader(b))
|
return um.UnmarshalCBOR(bytes.NewReader(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
func DumpActorState(code cid.Cid, b []byte) (interface{}, error) {
|
func DumpActorState(act *types.Actor, b []byte) (interface{}, error) {
|
||||||
if code == builtin0.AccountActorCodeID { // Account code special case
|
if builtin.IsAccountActor(act.Code) { // Account code special case
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
i := NewInvoker() // TODO: register builtins in init block
|
i := NewActorRegistry() // TODO: register builtins in init block
|
||||||
|
|
||||||
typ, ok := i.builtInState[code]
|
actInfo, ok := i.actors[act.Code]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, xerrors.Errorf("state type for actor %s not found", code)
|
return nil, xerrors.Errorf("state type for actor %s not found", act.Code)
|
||||||
}
|
|
||||||
|
|
||||||
rv := reflect.New(typ)
|
|
||||||
um, ok := rv.Interface().(cbg.CBORUnmarshaler)
|
|
||||||
if !ok {
|
|
||||||
return nil, xerrors.New("state type does not implement CBORUnmarshaler")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
um := actInfo.vmActor.State()
|
||||||
if err := um.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
|
if err := um.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
|
||||||
return nil, xerrors.Errorf("unmarshaling actor state: %w", err)
|
return nil, xerrors.Errorf("unmarshaling actor state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv.Elem().Interface(), nil
|
return um, nil
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ func (basicContract) InvokeSomething10(rt runtime.Runtime, params *basicParams)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInvokerBasic(t *testing.T) {
|
func TestInvokerBasic(t *testing.T) {
|
||||||
inv := Invoker{}
|
inv := ActorRegistry{}
|
||||||
code, err := inv.transform(basicContract{})
|
code, err := inv.transform(basicContract{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
@ -6,11 +6,13 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/go-state-types/exitcode"
|
"github.com/filecoin-project/go-state-types/exitcode"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
|
||||||
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -29,49 +31,47 @@ func init() {
|
|||||||
var EmptyObjectCid cid.Cid
|
var EmptyObjectCid cid.Cid
|
||||||
|
|
||||||
// TryCreateAccountActor creates account actors from only BLS/SECP256K1 addresses.
|
// TryCreateAccountActor creates account actors from only BLS/SECP256K1 addresses.
|
||||||
func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, aerrors.ActorError) {
|
func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, address.Address, aerrors.ActorError) {
|
||||||
if err := rt.chargeGasSafe(PricelistByEpoch(rt.height).OnCreateActor()); err != nil {
|
if err := rt.chargeGasSafe(PricelistByEpoch(rt.height).OnCreateActor()); err != nil {
|
||||||
return nil, err
|
return nil, address.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
addrID, err := rt.state.RegisterNewAddress(addr)
|
addrID, err := rt.state.RegisterNewAddress(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, aerrors.Escalate(err, "registering actor address")
|
return nil, address.Undef, aerrors.Escalate(err, "registering actor address")
|
||||||
}
|
}
|
||||||
|
|
||||||
act, aerr := makeActor(addr)
|
act, aerr := makeActor(actors.VersionForNetwork(rt.NetworkVersion()), addr)
|
||||||
if aerr != nil {
|
if aerr != nil {
|
||||||
return nil, aerr
|
return nil, address.Undef, aerr
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rt.state.SetActor(addrID, act); err != nil {
|
if err := rt.state.SetActor(addrID, act); err != nil {
|
||||||
return nil, aerrors.Escalate(err, "creating new actor failed")
|
return nil, address.Undef, aerrors.Escalate(err, "creating new actor failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := actors.SerializeParams(&addr)
|
p, err := actors.SerializeParams(&addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, aerrors.Escalate(err, "couldn't serialize params for actor construction")
|
return nil, address.Undef, aerrors.Escalate(err, "couldn't serialize params for actor construction")
|
||||||
}
|
}
|
||||||
// call constructor on account
|
// call constructor on account
|
||||||
|
|
||||||
_, aerr = rt.internalSend(builtin.SystemActorAddr, addrID, builtin.MethodsAccount.Constructor, big.Zero(), p)
|
_, aerr = rt.internalSend(builtin0.SystemActorAddr, addrID, builtin0.MethodsAccount.Constructor, big.Zero(), p)
|
||||||
if aerr != nil {
|
if aerr != nil {
|
||||||
return nil, aerrors.Wrap(aerr, "failed to invoke account constructor")
|
return nil, address.Undef, aerrors.Wrap(aerr, "failed to invoke account constructor")
|
||||||
}
|
}
|
||||||
|
|
||||||
act, err = rt.state.GetActor(addrID)
|
act, err = rt.state.GetActor(addrID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, aerrors.Escalate(err, "loading newly created actor failed")
|
return nil, address.Undef, aerrors.Escalate(err, "loading newly created actor failed")
|
||||||
}
|
}
|
||||||
return act, nil
|
return act, addrID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeActor(addr address.Address) (*types.Actor, aerrors.ActorError) {
|
func makeActor(ver actors.Version, addr address.Address) (*types.Actor, aerrors.ActorError) {
|
||||||
switch addr.Protocol() {
|
switch addr.Protocol() {
|
||||||
case address.BLS:
|
case address.BLS, address.SECP256K1:
|
||||||
return NewBLSAccountActor(), nil
|
return newAccountActor(ver), nil
|
||||||
case address.SECP256K1:
|
|
||||||
return NewSecp256k1AccountActor(), nil
|
|
||||||
case address.ID:
|
case address.ID:
|
||||||
return nil, aerrors.Newf(exitcode.SysErrInvalidReceiver, "no actor with given ID: %s", addr)
|
return nil, aerrors.Newf(exitcode.SysErrInvalidReceiver, "no actor with given ID: %s", addr)
|
||||||
case address.Actor:
|
case address.Actor:
|
||||||
@ -81,19 +81,19 @@ func makeActor(addr address.Address) (*types.Actor, aerrors.ActorError) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBLSAccountActor() *types.Actor {
|
func newAccountActor(ver actors.Version) *types.Actor {
|
||||||
|
// TODO: ActorsUpgrade use a global actor registry?
|
||||||
|
var code cid.Cid
|
||||||
|
switch ver {
|
||||||
|
case actors.Version0:
|
||||||
|
code = builtin0.AccountActorCodeID
|
||||||
|
case actors.Version2:
|
||||||
|
code = builtin2.AccountActorCodeID
|
||||||
|
default:
|
||||||
|
panic("unsupported actors version")
|
||||||
|
}
|
||||||
nact := &types.Actor{
|
nact := &types.Actor{
|
||||||
Code: builtin.AccountActorCodeID,
|
Code: code,
|
||||||
Balance: types.NewInt(0),
|
|
||||||
Head: EmptyObjectCid,
|
|
||||||
}
|
|
||||||
|
|
||||||
return nact
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSecp256k1AccountActor() *types.Actor {
|
|
||||||
nact := &types.Actor{
|
|
||||||
Code: builtin.AccountActorCodeID,
|
|
||||||
Balance: types.NewInt(0),
|
Balance: types.NewInt(0),
|
||||||
Head: EmptyObjectCid,
|
Head: EmptyObjectCid,
|
||||||
}
|
}
|
||||||
|
@ -9,14 +9,13 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
|
||||||
"github.com/filecoin-project/go-state-types/cbor"
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/filecoin-project/go-state-types/exitcode"
|
"github.com/filecoin-project/go-state-types/exitcode"
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
rtt "github.com/filecoin-project/go-state-types/rt"
|
rtt "github.com/filecoin-project/go-state-types/rt"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
rt0 "github.com/filecoin-project/specs-actors/actors/runtime"
|
rt0 "github.com/filecoin-project/specs-actors/actors/runtime"
|
||||||
|
rt2 "github.com/filecoin-project/specs-actors/v2/actors/runtime"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
ipldcbor "github.com/ipfs/go-ipld-cbor"
|
ipldcbor "github.com/ipfs/go-ipld-cbor"
|
||||||
"go.opencensus.io/trace"
|
"go.opencensus.io/trace"
|
||||||
@ -28,8 +27,33 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
msg types.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Message) Caller() address.Address {
|
||||||
|
if m.msg.From.Protocol() != address.ID {
|
||||||
|
panic("runtime message has a non-ID caller")
|
||||||
|
}
|
||||||
|
return m.msg.From
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Message) Receiver() address.Address {
|
||||||
|
if m.msg.To != address.Undef && m.msg.To.Protocol() != address.ID {
|
||||||
|
panic("runtime message has a non-ID receiver")
|
||||||
|
}
|
||||||
|
return m.msg.To
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
type Runtime struct {
|
||||||
types.Message
|
rt0.Message
|
||||||
rt0.Syscalls
|
rt0.Syscalls
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@ -110,6 +134,7 @@ func (rt *Runtime) StorePut(x cbor.Marshaler) cid.Cid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var _ rt0.Runtime = (*Runtime)(nil)
|
var _ rt0.Runtime = (*Runtime)(nil)
|
||||||
|
var _ rt2.Runtime = (*Runtime)(nil)
|
||||||
|
|
||||||
func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) {
|
func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) {
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -122,7 +147,11 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
|||||||
//log.Desugar().WithOptions(zap.AddStacktrace(zapcore.ErrorLevel)).
|
//log.Desugar().WithOptions(zap.AddStacktrace(zapcore.ErrorLevel)).
|
||||||
//Sugar().Errorf("spec actors failure: %s", r)
|
//Sugar().Errorf("spec actors failure: %s", r)
|
||||||
log.Errorf("spec actors failure: %s", r)
|
log.Errorf("spec actors failure: %s", r)
|
||||||
aerr = aerrors.Newf(1, "spec actors failure: %s", r)
|
if rt.NetworkVersion() <= network.Version3 {
|
||||||
|
aerr = aerrors.Newf(1, "spec actors failure: %s", r)
|
||||||
|
} else {
|
||||||
|
aerr = aerrors.Newf(exitcode.SysErrReserved1, "spec actors failure: %s", r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -215,12 +244,9 @@ func (rt *Runtime) NewActorAddress() address.Address {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) {
|
func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) {
|
||||||
if !builtin.IsBuiltinActor(codeID) {
|
act, aerr := rt.vm.areg.Create(codeID, rt)
|
||||||
rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only create built-in actors.")
|
if aerr != nil {
|
||||||
}
|
rt.Abortf(aerr.RetCode(), aerr.Error())
|
||||||
|
|
||||||
if builtin.IsSingletonActor(codeID) {
|
|
||||||
rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only have one instance of singleton actors.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := rt.state.GetActor(address)
|
_, err := rt.state.GetActor(address)
|
||||||
@ -230,12 +256,7 @@ func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) {
|
|||||||
|
|
||||||
rt.chargeGas(rt.Pricelist().OnCreateActor())
|
rt.chargeGas(rt.Pricelist().OnCreateActor())
|
||||||
|
|
||||||
err = rt.state.SetActor(address, &types.Actor{
|
err = rt.state.SetActor(address, act)
|
||||||
Code: codeID,
|
|
||||||
Head: EmptyObjectCid,
|
|
||||||
Nonce: 0,
|
|
||||||
Balance: big.Zero(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(aerrors.Fatalf("creating actor entry: %v", err))
|
panic(aerrors.Fatalf("creating actor entry: %v", err))
|
||||||
}
|
}
|
||||||
@ -459,7 +480,7 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) finilizeGasTracing() {
|
func (rt *Runtime) finilizeGasTracing() {
|
||||||
if enableTracing {
|
if EnableGasTracing {
|
||||||
if rt.lastGasCharge != nil {
|
if rt.lastGasCharge != nil {
|
||||||
rt.lastGasCharge.TimeTaken = time.Since(rt.lastGasChargeTime)
|
rt.lastGasCharge.TimeTaken = time.Since(rt.lastGasChargeTime)
|
||||||
}
|
}
|
||||||
@ -491,11 +512,9 @@ func (rt *Runtime) chargeGasFunc(skip int) func(GasCharge) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var enableTracing = false
|
|
||||||
|
|
||||||
func (rt *Runtime) chargeGasInternal(gas GasCharge, skip int) aerrors.ActorError {
|
func (rt *Runtime) chargeGasInternal(gas GasCharge, skip int) aerrors.ActorError {
|
||||||
toUse := gas.Total()
|
toUse := gas.Total()
|
||||||
if enableTracing {
|
if EnableGasTracing {
|
||||||
var callers [10]uintptr
|
var callers [10]uintptr
|
||||||
|
|
||||||
cout := 0 //gruntime.Callers(2+skip, callers[:])
|
cout := 0 //gruntime.Callers(2+skip, callers[:])
|
||||||
|
@ -45,3 +45,23 @@ func TestRuntimePutErrors(t *testing.T) {
|
|||||||
rt.StorePut(&NotAVeryGoodMarshaler{})
|
rt.StorePut(&NotAVeryGoodMarshaler{})
|
||||||
t.Error("expected panic")
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,6 +8,8 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
block "github.com/ipfs/go-block-format"
|
block "github.com/ipfs/go-block-format"
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
@ -23,7 +25,6 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/filecoin-project/go-state-types/exitcode"
|
"github.com/filecoin-project/go-state-types/exitcode"
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
@ -130,7 +131,15 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres
|
|||||||
rt.Abortf(exitcode.SysErrInvalidReceiver, "resolve msg.From address failed")
|
rt.Abortf(exitcode.SysErrInvalidReceiver, "resolve msg.From address failed")
|
||||||
}
|
}
|
||||||
vmm.From = resF
|
vmm.From = resF
|
||||||
rt.Message = vmm
|
|
||||||
|
if vm.ntwkVersion(ctx, vm.blockHeight) <= network.Version3 {
|
||||||
|
rt.Message = &vmm
|
||||||
|
} else {
|
||||||
|
resT, _ := rt.ResolveAddress(msg.To)
|
||||||
|
// may be set to undef if recipient doesn't exist yet
|
||||||
|
vmm.To = resT
|
||||||
|
rt.Message = &Message{msg: vmm}
|
||||||
|
}
|
||||||
|
|
||||||
return rt
|
return rt
|
||||||
}
|
}
|
||||||
@ -152,7 +161,7 @@ type VM struct {
|
|||||||
cst *cbor.BasicIpldStore
|
cst *cbor.BasicIpldStore
|
||||||
buf *bufbstore.BufferedBS
|
buf *bufbstore.BufferedBS
|
||||||
blockHeight abi.ChainEpoch
|
blockHeight abi.ChainEpoch
|
||||||
inv *Invoker
|
areg *ActorRegistry
|
||||||
rand Rand
|
rand Rand
|
||||||
circSupplyCalc CircSupplyCalculator
|
circSupplyCalc CircSupplyCalculator
|
||||||
ntwkVersion NtwkVersionGetter
|
ntwkVersion NtwkVersionGetter
|
||||||
@ -186,7 +195,7 @@ func NewVM(ctx context.Context, opts *VMOpts) (*VM, error) {
|
|||||||
cst: cst,
|
cst: cst,
|
||||||
buf: buf,
|
buf: buf,
|
||||||
blockHeight: opts.Epoch,
|
blockHeight: opts.Epoch,
|
||||||
inv: NewInvoker(),
|
areg: NewActorRegistry(),
|
||||||
rand: opts.Rand, // TODO: Probably should be a syscall
|
rand: opts.Rand, // TODO: Probably should be a syscall
|
||||||
circSupplyCalc: opts.CircSupplyCalc,
|
circSupplyCalc: opts.CircSupplyCalc,
|
||||||
ntwkVersion: opts.NtwkVersion,
|
ntwkVersion: opts.NtwkVersion,
|
||||||
@ -227,7 +236,7 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
|||||||
}
|
}
|
||||||
|
|
||||||
rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac)
|
rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac)
|
||||||
if enableTracing {
|
if EnableGasTracing {
|
||||||
rt.lastGasChargeTime = start
|
rt.lastGasChargeTime = start
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
rt.lastGasChargeTime = parent.lastGasChargeTime
|
rt.lastGasChargeTime = parent.lastGasChargeTime
|
||||||
@ -256,11 +265,24 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
|||||||
toActor, err := st.GetActor(msg.To)
|
toActor, err := st.GetActor(msg.To)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||||
a, err := TryCreateAccountActor(rt, msg.To)
|
a, aid, err := TryCreateAccountActor(rt, msg.To)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, aerrors.Wrapf(err, "could not create account")
|
return nil, aerrors.Wrapf(err, "could not create account")
|
||||||
}
|
}
|
||||||
toActor = a
|
toActor = a
|
||||||
|
if vm.ntwkVersion(ctx, vm.blockHeight) <= network.Version3 {
|
||||||
|
// Leave the rt.Message as is
|
||||||
|
} else {
|
||||||
|
nmsg := Message{
|
||||||
|
msg: types.Message{
|
||||||
|
To: aid,
|
||||||
|
From: rt.Message.Caller(),
|
||||||
|
Value: rt.Message.ValueReceived(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rt.Message = &nmsg
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, aerrors.Escalate(err, "getting actor")
|
return nil, aerrors.Escalate(err, "getting actor")
|
||||||
}
|
}
|
||||||
@ -403,7 +425,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this should never happen, but is currently still exercised by some tests
|
// this should never happen, but is currently still exercised by some tests
|
||||||
if !fromActor.IsAccountActor() {
|
if !builtin.IsAccountActor(fromActor.Code) {
|
||||||
gasOutputs := ZeroGasOutputs()
|
gasOutputs := ZeroGasOutputs()
|
||||||
gasOutputs.MinerPenalty = minerPenaltyAmount
|
gasOutputs.MinerPenalty = minerPenaltyAmount
|
||||||
return &ApplyRet{
|
return &ApplyRet{
|
||||||
@ -741,15 +763,15 @@ func (vm *VM) Invoke(act *types.Actor, rt *Runtime, method abi.MethodNum, params
|
|||||||
defer func() {
|
defer func() {
|
||||||
rt.ctx = oldCtx
|
rt.ctx = oldCtx
|
||||||
}()
|
}()
|
||||||
ret, err := vm.inv.Invoke(act.Code, rt, method, params)
|
ret, err := vm.areg.Invoke(act.Code, rt, method, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VM) SetInvoker(i *Invoker) {
|
func (vm *VM) SetInvoker(i *ActorRegistry) {
|
||||||
vm.inv = i
|
vm.areg = i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VM) GetNtwkVersion(ctx context.Context, ce abi.ChainEpoch) network.Version {
|
func (vm *VM) GetNtwkVersion(ctx context.Context, ce abi.ChainEpoch) network.Version {
|
||||||
|
@ -81,7 +81,7 @@ func (w *Wallet) findKey(addr address.Address) (*Key, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ki, err := w.keystore.Get(KNamePrefix + addr.String())
|
ki, err := w.tryFind(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if xerrors.Is(err, types.ErrKeyInfoNotFound) {
|
if xerrors.Is(err, types.ErrKeyInfoNotFound) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -96,6 +96,42 @@ func (w *Wallet) findKey(addr address.Address) (*Key, error) {
|
|||||||
return k, nil
|
return k, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Wallet) tryFind(addr address.Address) (types.KeyInfo, error) {
|
||||||
|
|
||||||
|
ki, err := w.keystore.Get(KNamePrefix + addr.String())
|
||||||
|
if err == nil {
|
||||||
|
return ki, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !xerrors.Is(err, types.ErrKeyInfoNotFound) {
|
||||||
|
return types.KeyInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We got an ErrKeyInfoNotFound error
|
||||||
|
// Try again, this time with the testnet prefix
|
||||||
|
|
||||||
|
aChars := []rune(addr.String())
|
||||||
|
prefixRunes := []rune(address.TestnetPrefix)
|
||||||
|
if len(prefixRunes) != 1 {
|
||||||
|
return types.KeyInfo{}, xerrors.Errorf("unexpected prefix length: %d", len(prefixRunes))
|
||||||
|
}
|
||||||
|
|
||||||
|
aChars[0] = prefixRunes[0]
|
||||||
|
ki, err = w.keystore.Get(KNamePrefix + string(aChars))
|
||||||
|
if err != nil {
|
||||||
|
return types.KeyInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We found it with the testnet prefix
|
||||||
|
// Add this KeyInfo with the mainnet prefix address string
|
||||||
|
err = w.keystore.Put(KNamePrefix+addr.String(), ki)
|
||||||
|
if err != nil {
|
||||||
|
return types.KeyInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ki, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (w *Wallet) Export(addr address.Address) (*types.KeyInfo, error) {
|
func (w *Wallet) Export(addr address.Address) (*types.KeyInfo, error) {
|
||||||
k, err := w.findKey(addr)
|
k, err := w.findKey(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -129,6 +165,7 @@ func (w *Wallet) ListAddrs() ([]address.Address, error) {
|
|||||||
|
|
||||||
sort.Strings(all)
|
sort.Strings(all)
|
||||||
|
|
||||||
|
seen := map[address.Address]struct{}{}
|
||||||
out := make([]address.Address, 0, len(all))
|
out := make([]address.Address, 0, len(all))
|
||||||
for _, a := range all {
|
for _, a := range all {
|
||||||
if strings.HasPrefix(a, KNamePrefix) {
|
if strings.HasPrefix(a, KNamePrefix) {
|
||||||
@ -137,10 +174,19 @@ func (w *Wallet) ListAddrs() ([]address.Address, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("converting name to address: %w", err)
|
return nil, xerrors.Errorf("converting name to address: %w", err)
|
||||||
}
|
}
|
||||||
|
if _, ok := seen[addr]; ok {
|
||||||
|
continue // got duplicate with a different prefix
|
||||||
|
}
|
||||||
|
seen[addr] = struct{}{}
|
||||||
|
|
||||||
out = append(out, addr)
|
out = append(out, addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort.Slice(out, func(i, j int) bool {
|
||||||
|
return out[i].String() < out[j].String()
|
||||||
|
})
|
||||||
|
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
125
cli/backup.go
Normal file
125
cli/backup.go
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
logging "github.com/ipfs/go-log/v2"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-jsonrpc"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/lib/backupds"
|
||||||
|
"github.com/filecoin-project/lotus/node/repo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BackupAPI interface {
|
||||||
|
CreateBackup(ctx context.Context, fpath string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type BackupApiFn func(ctx *cli.Context) (BackupAPI, jsonrpc.ClientCloser, error)
|
||||||
|
|
||||||
|
func BackupCmd(repoFlag string, rt repo.RepoType, getApi BackupApiFn) *cli.Command {
|
||||||
|
var offlineBackup = func(cctx *cli.Context) error {
|
||||||
|
logging.SetLogLevel("badger", "ERROR") // nolint:errcheck
|
||||||
|
|
||||||
|
repoPath := cctx.String(repoFlag)
|
||||||
|
r, err := repo.NewFS(repoPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := r.Exists()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return xerrors.Errorf("repo at '%s' is not initialized", cctx.String(repoFlag))
|
||||||
|
}
|
||||||
|
|
||||||
|
lr, err := r.LockRO(rt)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("locking repo: %w", err)
|
||||||
|
}
|
||||||
|
defer lr.Close() // nolint:errcheck
|
||||||
|
|
||||||
|
mds, err := lr.Datastore("/metadata")
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting metadata datastore: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bds := backupds.Wrap(mds)
|
||||||
|
|
||||||
|
fpath, err := homedir.Expand(cctx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("expanding file path: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("opening backup file %s: %w", fpath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := bds.Backup(out); err != nil {
|
||||||
|
if cerr := out.Close(); cerr != nil {
|
||||||
|
log.Errorw("error closing backup file while handling backup error", "closeErr", cerr, "backupErr", err)
|
||||||
|
}
|
||||||
|
return xerrors.Errorf("backup error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := out.Close(); err != nil {
|
||||||
|
return xerrors.Errorf("closing backup file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var onlineBackup = func(cctx *cli.Context) error {
|
||||||
|
api, closer, err := getApi(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting api: %w (if the node isn't running you can use the --offline flag)", err)
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
|
||||||
|
err = api.CreateBackup(ReqContext(cctx), cctx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Success")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "backup",
|
||||||
|
Usage: "Create node metadata backup",
|
||||||
|
Description: `The backup command writes a copy of node metadata under the specified path
|
||||||
|
|
||||||
|
Online backups:
|
||||||
|
For security reasons, the daemon must be have LOTUS_BACKUP_BASE_PATH env var set
|
||||||
|
to a path where backup files are supposed to be saved, and the path specified in
|
||||||
|
this command must be within this base path`,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "offline",
|
||||||
|
Usage: "create backup without the node running",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ArgsUsage: "[backup file path]",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if cctx.Args().Len() != 1 {
|
||||||
|
return xerrors.Errorf("expected 1 argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
if cctx.Bool("offline") {
|
||||||
|
return offlineBackup(cctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return onlineBackup(cctx)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
159
cli/chain.go
159
cli/chain.go
@ -8,6 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -27,9 +28,10 @@ import (
|
|||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
lapi "github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
types "github.com/filecoin-project/lotus/chain/types"
|
types "github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,6 +52,7 @@ var chainCmd = &cli.Command{
|
|||||||
chainExportCmd,
|
chainExportCmd,
|
||||||
slashConsensusFault,
|
slashConsensusFault,
|
||||||
chainGasPriceCmd,
|
chainGasPriceCmd,
|
||||||
|
chainInspectUsage,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +162,7 @@ var chainGetBlock = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiMsgCids(in []api.Message) []cid.Cid {
|
func apiMsgCids(in []lapi.Message) []cid.Cid {
|
||||||
out := make([]cid.Cid, len(in))
|
out := make([]cid.Cid, len(in))
|
||||||
for k, v := range in {
|
for k, v := range in {
|
||||||
out[k] = v.Cid
|
out[k] = v.Cid
|
||||||
@ -375,6 +378,143 @@ var chainSetHeadCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var chainInspectUsage = &cli.Command{
|
||||||
|
Name: "inspect-usage",
|
||||||
|
Usage: "Inspect block space usage of a given tipset",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "tipset",
|
||||||
|
Usage: "specify tipset to view block space usage of",
|
||||||
|
Value: "@head",
|
||||||
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "length",
|
||||||
|
Usage: "length of chain to inspect block space usage for",
|
||||||
|
Value: 1,
|
||||||
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "num-results",
|
||||||
|
Usage: "number of results to print per category",
|
||||||
|
Value: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
ts, err := LoadTipSet(ctx, cctx, api)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cur := ts
|
||||||
|
var msgs []lapi.Message
|
||||||
|
for i := 0; i < cctx.Int("length"); i++ {
|
||||||
|
pmsgs, err := api.ChainGetParentMessages(ctx, cur.Blocks()[0].Cid())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msgs = append(msgs, pmsgs...)
|
||||||
|
|
||||||
|
next, err := api.ChainGetTipSet(ctx, cur.Parents())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = next
|
||||||
|
}
|
||||||
|
|
||||||
|
codeCache := make(map[address.Address]cid.Cid)
|
||||||
|
|
||||||
|
lookupActorCode := func(a address.Address) (cid.Cid, error) {
|
||||||
|
c, ok := codeCache[a]
|
||||||
|
if ok {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
act, err := api.StateGetActor(ctx, a, ts.Key())
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
codeCache[a] = act.Code
|
||||||
|
return act.Code, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
bySender := make(map[string]int64)
|
||||||
|
byDest := make(map[string]int64)
|
||||||
|
byMethod := make(map[string]int64)
|
||||||
|
|
||||||
|
var sum int64
|
||||||
|
for _, m := range msgs {
|
||||||
|
bySender[m.Message.From.String()] += m.Message.GasLimit
|
||||||
|
byDest[m.Message.To.String()] += m.Message.GasLimit
|
||||||
|
sum += m.Message.GasLimit
|
||||||
|
|
||||||
|
code, err := lookupActorCode(m.Message.To)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mm := stmgr.MethodsMap[code][m.Message.Method]
|
||||||
|
|
||||||
|
byMethod[mm.Name] += m.Message.GasLimit
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type keyGasPair struct {
|
||||||
|
Key string
|
||||||
|
Gas int64
|
||||||
|
}
|
||||||
|
|
||||||
|
mapToSortedKvs := func(m map[string]int64) []keyGasPair {
|
||||||
|
var vals []keyGasPair
|
||||||
|
for k, v := range m {
|
||||||
|
vals = append(vals, keyGasPair{
|
||||||
|
Key: k,
|
||||||
|
Gas: v,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
sort.Slice(vals, func(i, j int) bool {
|
||||||
|
return vals[i].Gas > vals[j].Gas
|
||||||
|
})
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
senderVals := mapToSortedKvs(bySender)
|
||||||
|
destVals := mapToSortedKvs(byDest)
|
||||||
|
methodVals := mapToSortedKvs(byMethod)
|
||||||
|
|
||||||
|
numRes := cctx.Int("num-results")
|
||||||
|
|
||||||
|
fmt.Printf("Total Gas Limit: %d\n", sum)
|
||||||
|
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.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.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
var chainListCmd = &cli.Command{
|
var chainListCmd = &cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "View a segment of the chain",
|
Usage: "View a segment of the chain",
|
||||||
@ -648,7 +788,7 @@ var chainGetCmd = &cli.Command{
|
|||||||
|
|
||||||
type apiIpldStore struct {
|
type apiIpldStore struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
api api.FullNode
|
api lapi.FullNode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ht *apiIpldStore) Context() context.Context {
|
func (ht *apiIpldStore) Context() context.Context {
|
||||||
@ -676,7 +816,7 @@ func (ht *apiIpldStore) Put(ctx context.Context, v interface{}) (cid.Cid, error)
|
|||||||
panic("No mutations allowed")
|
panic("No mutations allowed")
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleAmt(ctx context.Context, api api.FullNode, r cid.Cid) error {
|
func handleAmt(ctx context.Context, api lapi.FullNode, r cid.Cid) error {
|
||||||
s := &apiIpldStore{ctx, api}
|
s := &apiIpldStore{ctx, api}
|
||||||
mp, err := adt.AsArray(s, r)
|
mp, err := adt.AsArray(s, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -689,7 +829,7 @@ func handleAmt(ctx context.Context, api api.FullNode, r cid.Cid) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHamtEpoch(ctx context.Context, api api.FullNode, r cid.Cid) error {
|
func handleHamtEpoch(ctx context.Context, api lapi.FullNode, r cid.Cid) error {
|
||||||
s := &apiIpldStore{ctx, api}
|
s := &apiIpldStore{ctx, api}
|
||||||
mp, err := adt.AsMap(s, r)
|
mp, err := adt.AsMap(s, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -707,7 +847,7 @@ func handleHamtEpoch(ctx context.Context, api api.FullNode, r cid.Cid) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHamtAddress(ctx context.Context, api api.FullNode, r cid.Cid) error {
|
func handleHamtAddress(ctx context.Context, api lapi.FullNode, r cid.Cid) error {
|
||||||
s := &apiIpldStore{ctx, api}
|
s := &apiIpldStore{ctx, api}
|
||||||
mp, err := adt.AsMap(s, r)
|
mp, err := adt.AsMap(s, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -930,13 +1070,20 @@ var chainExportCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var last bool
|
||||||
for b := range stream {
|
for b := range stream {
|
||||||
|
last = len(b) == 0
|
||||||
|
|
||||||
_, err := fi.Write(b)
|
_, err := fi.Write(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !last {
|
||||||
|
return xerrors.Errorf("incomplete export (remote connection lost?)")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
15
cli/cmd.go
15
cli/cmd.go
@ -216,6 +216,13 @@ func GetAPI(ctx *cli.Context) (api.Common, jsonrpc.ClientCloser, error) {
|
|||||||
log.Errorf("repoType type does not match the type of repo.RepoType")
|
log.Errorf("repoType type does not match the type of repo.RepoType")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tn, ok := ctx.App.Metadata["testnode-storage"]; ok {
|
||||||
|
return tn.(api.StorageMiner), func() {}, nil
|
||||||
|
}
|
||||||
|
if tn, ok := ctx.App.Metadata["testnode-full"]; ok {
|
||||||
|
return tn.(api.FullNode), func() {}, nil
|
||||||
|
}
|
||||||
|
|
||||||
addr, headers, err := GetRawAPI(ctx, t)
|
addr, headers, err := GetRawAPI(ctx, t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -225,6 +232,10 @@ func GetAPI(ctx *cli.Context) (api.Common, jsonrpc.ClientCloser, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetFullNodeAPI(ctx *cli.Context) (api.FullNode, jsonrpc.ClientCloser, error) {
|
func GetFullNodeAPI(ctx *cli.Context) (api.FullNode, jsonrpc.ClientCloser, error) {
|
||||||
|
if tn, ok := ctx.App.Metadata["testnode-full"]; ok {
|
||||||
|
return tn.(api.FullNode), func() {}, nil
|
||||||
|
}
|
||||||
|
|
||||||
addr, headers, err := GetRawAPI(ctx, repo.FullNode)
|
addr, headers, err := GetRawAPI(ctx, repo.FullNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -234,6 +245,10 @@ func GetFullNodeAPI(ctx *cli.Context) (api.FullNode, jsonrpc.ClientCloser, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetStorageMinerAPI(ctx *cli.Context, opts ...jsonrpc.Option) (api.StorageMiner, jsonrpc.ClientCloser, error) {
|
func GetStorageMinerAPI(ctx *cli.Context, opts ...jsonrpc.Option) (api.StorageMiner, jsonrpc.ClientCloser, error) {
|
||||||
|
if tn, ok := ctx.App.Metadata["testnode-storage"]; ok {
|
||||||
|
return tn.(api.StorageMiner), func() {}, nil
|
||||||
|
}
|
||||||
|
|
||||||
addr, headers, err := GetRawAPI(ctx, repo.StorageMiner)
|
addr, headers, err := GetRawAPI(ctx, repo.StorageMiner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
69
cli/mpool.go
69
cli/mpool.go
@ -164,14 +164,6 @@ var mpoolSub = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type statBucket struct {
|
|
||||||
msgs map[uint64]*types.SignedMessage
|
|
||||||
}
|
|
||||||
type mpStat struct {
|
|
||||||
addr string
|
|
||||||
past, cur, future uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
var mpoolStat = &cli.Command{
|
var mpoolStat = &cli.Command{
|
||||||
Name: "stat",
|
Name: "stat",
|
||||||
Usage: "print mempool stats",
|
Usage: "print mempool stats",
|
||||||
@ -180,6 +172,11 @@ var mpoolStat = &cli.Command{
|
|||||||
Name: "local",
|
Name: "local",
|
||||||
Usage: "print stats for addresses in local wallet only",
|
Usage: "print stats for addresses in local wallet only",
|
||||||
},
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "basefee-lookback",
|
||||||
|
Usage: "number of blocks to look back for minimum basefee",
|
||||||
|
Value: 60,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
api, closer, err := GetFullNodeAPI(cctx)
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
@ -194,6 +191,20 @@ var mpoolStat = &cli.Command{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("getting chain head: %w", err)
|
return xerrors.Errorf("getting chain head: %w", err)
|
||||||
}
|
}
|
||||||
|
currBF := ts.Blocks()[0].ParentBaseFee
|
||||||
|
minBF := currBF
|
||||||
|
{
|
||||||
|
currTs := ts
|
||||||
|
for i := 0; i < cctx.Int("basefee-lookback"); i++ {
|
||||||
|
currTs, err = api.ChainGetTipSet(ctx, currTs.Parents())
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("walking chain: %w", err)
|
||||||
|
}
|
||||||
|
if newBF := currTs.Blocks()[0].ParentBaseFee; newBF.LessThan(minBF) {
|
||||||
|
minBF = newBF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var filter map[address.Address]struct{}
|
var filter map[address.Address]struct{}
|
||||||
if cctx.Bool("local") {
|
if cctx.Bool("local") {
|
||||||
@ -214,8 +225,16 @@ var mpoolStat = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
buckets := map[address.Address]*statBucket{}
|
type statBucket struct {
|
||||||
|
msgs map[uint64]*types.SignedMessage
|
||||||
|
}
|
||||||
|
type mpStat struct {
|
||||||
|
addr string
|
||||||
|
past, cur, future uint64
|
||||||
|
belowCurr, belowPast uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
buckets := map[address.Address]*statBucket{}
|
||||||
for _, v := range msgs {
|
for _, v := range msgs {
|
||||||
if filter != nil {
|
if filter != nil {
|
||||||
if _, has := filter[v.Message.From]; !has {
|
if _, has := filter[v.Message.From]; !has {
|
||||||
@ -252,23 +271,27 @@ var mpoolStat = &cli.Command{
|
|||||||
cur++
|
cur++
|
||||||
}
|
}
|
||||||
|
|
||||||
past := uint64(0)
|
var s mpStat
|
||||||
future := uint64(0)
|
s.addr = a.String()
|
||||||
|
|
||||||
for _, m := range bkt.msgs {
|
for _, m := range bkt.msgs {
|
||||||
if m.Message.Nonce < act.Nonce {
|
if m.Message.Nonce < act.Nonce {
|
||||||
past++
|
s.past++
|
||||||
|
} else if m.Message.Nonce > cur {
|
||||||
|
s.future++
|
||||||
|
} else {
|
||||||
|
s.cur++
|
||||||
}
|
}
|
||||||
if m.Message.Nonce > cur {
|
|
||||||
future++
|
if m.Message.GasFeeCap.LessThan(currBF) {
|
||||||
|
s.belowCurr++
|
||||||
|
}
|
||||||
|
if m.Message.GasFeeCap.LessThan(minBF) {
|
||||||
|
s.belowPast++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out = append(out, mpStat{
|
out = append(out, s)
|
||||||
addr: a.String(),
|
|
||||||
past: past,
|
|
||||||
cur: cur - act.Nonce,
|
|
||||||
future: future,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(out, func(i, j int) bool {
|
sort.Slice(out, func(i, j int) bool {
|
||||||
@ -281,12 +304,14 @@ var mpoolStat = &cli.Command{
|
|||||||
total.past += stat.past
|
total.past += stat.past
|
||||||
total.cur += stat.cur
|
total.cur += stat.cur
|
||||||
total.future += stat.future
|
total.future += stat.future
|
||||||
|
total.belowCurr += stat.belowCurr
|
||||||
|
total.belowPast += stat.belowPast
|
||||||
|
|
||||||
fmt.Printf("%s: past: %d, cur: %d, future: %d\n", stat.addr, stat.past, stat.cur, stat.future)
|
fmt.Printf("%s: Nonce past: %d, cur: %d, future: %d; FeeCap cur: %d, min-%d: %d \n", stat.addr, stat.past, stat.cur, stat.future, stat.belowCurr, cctx.Int("basefee-lookback"), stat.belowPast)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("-----")
|
fmt.Println("-----")
|
||||||
fmt.Printf("total: past: %d, cur: %d, future: %d\n", total.past, total.cur, total.future)
|
fmt.Printf("total: Nonce past: %d, cur: %d, future: %d; FeeCap cur: %d, min-%d: %d \n", total.past, total.cur, total.future, total.belowCurr, cctx.Int("basefee-lookback"), total.belowPast)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
@ -9,6 +9,10 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
@ -20,7 +24,6 @@ import (
|
|||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||||
|
|
||||||
@ -356,7 +359,7 @@ var msigProposeCmd = &cli.Command{
|
|||||||
return fmt.Errorf("failed to look up multisig %s: %w", msig, err)
|
return fmt.Errorf("failed to look up multisig %s: %w", msig, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !act.IsMultisigActor() {
|
if !builtin.IsMultisigActor(act.Code) {
|
||||||
return fmt.Errorf("actor %s is not a multisig actor", msig)
|
return fmt.Errorf("actor %s is not a multisig actor", msig)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1029,7 +1032,7 @@ var msigLockProposeCmd = &cli.Command{
|
|||||||
return actErr
|
return actErr
|
||||||
}
|
}
|
||||||
|
|
||||||
msgCid, err := api.MsigPropose(ctx, msig, msig, big.Zero(), from, uint64(builtin.MethodsMultisig.LockBalance), params)
|
msgCid, err := api.MsigPropose(ctx, msig, msig, big.Zero(), from, uint64(builtin2.MethodsMultisig.LockBalance), params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1126,7 +1129,7 @@ var msigLockApproveCmd = &cli.Command{
|
|||||||
return actErr
|
return actErr
|
||||||
}
|
}
|
||||||
|
|
||||||
msgCid, err := api.MsigApprove(ctx, msig, txid, prop, msig, big.Zero(), from, uint64(builtin.MethodsMultisig.LockBalance), params)
|
msgCid, err := api.MsigApprove(ctx, msig, txid, prop, msig, big.Zero(), from, uint64(builtin2.MethodsMultisig.LockBalance), params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1218,7 +1221,7 @@ var msigLockCancelCmd = &cli.Command{
|
|||||||
return actErr
|
return actErr
|
||||||
}
|
}
|
||||||
|
|
||||||
msgCid, err := api.MsigCancel(ctx, msig, txid, msig, big.Zero(), from, uint64(builtin.MethodsMultisig.LockBalance), params)
|
msgCid, err := api.MsigCancel(ctx, msig, txid, msig, big.Zero(), from, uint64(builtin2.MethodsMultisig.LockBalance), params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
10
cli/paych.go
10
cli/paych.go
@ -14,10 +14,10 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
types "github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var paychCmd = &cli.Command{
|
var paychCmd = &cli.Command{
|
||||||
@ -404,7 +404,7 @@ var paychVoucherCheckCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sv, err := types.DecodeSignedVoucher(cctx.Args().Get(1))
|
sv, err := paych.DecodeSignedVoucher(cctx.Args().Get(1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -440,7 +440,7 @@ var paychVoucherAddCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sv, err := types.DecodeSignedVoucher(cctx.Args().Get(1))
|
sv, err := paych.DecodeSignedVoucher(cctx.Args().Get(1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -598,7 +598,7 @@ var paychVoucherSubmitCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sv, err := types.DecodeSignedVoucher(cctx.Args().Get(1))
|
sv, err := paych.DecodeSignedVoucher(cctx.Args().Get(1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
126
cli/state.go
126
cli/state.go
@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
@ -14,7 +15,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
"github.com/multiformats/go-multiaddr"
|
"github.com/multiformats/go-multiaddr"
|
||||||
|
|
||||||
@ -30,10 +31,9 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/go-state-types/exitcode"
|
"github.com/filecoin-project/go-state-types/exitcode"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"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/api/apibstore"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
@ -72,6 +72,7 @@ var stateCmd = &cli.Command{
|
|||||||
stateMsgCostCmd,
|
stateMsgCostCmd,
|
||||||
stateMinerInfo,
|
stateMinerInfo,
|
||||||
stateMarketCmd,
|
stateMarketCmd,
|
||||||
|
stateExecTraceCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,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{
|
var stateReplaySetCmd = &cli.Command{
|
||||||
Name: "replay",
|
Name: "replay",
|
||||||
Usage: "Replay a particular message within a tipset",
|
Usage: "Replay a particular message within a tipset",
|
||||||
@ -825,6 +894,10 @@ var stateComputeStateCmd = &cli.Command{
|
|||||||
Name: "json",
|
Name: "json",
|
||||||
Usage: "generate json output",
|
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 {
|
Action: func(cctx *cli.Context) error {
|
||||||
api, closer, err := GetFullNodeAPI(cctx)
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
@ -864,9 +937,26 @@ var stateComputeStateCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stout, err := api.StateCompute(ctx, h, msgs, ts.Key())
|
var stout *lapi.ComputeStateOutput
|
||||||
if err != nil {
|
if csofile := cctx.String("compute-state-output"); csofile != "" {
|
||||||
return err
|
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") {
|
if cctx.Bool("json") {
|
||||||
@ -1534,28 +1624,18 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var target runtime.Invokee
|
// TODO: consider moving this to a dedicated helper
|
||||||
for _, actor := range exported.BuiltinActors() {
|
actMeta, ok := stmgr.MethodsMap[act]
|
||||||
if actor.Code() == act {
|
if !ok {
|
||||||
target = actor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if target == nil {
|
|
||||||
return nil, fmt.Errorf("unknown actor %s", act)
|
return nil, fmt.Errorf("unknown actor %s", act)
|
||||||
}
|
}
|
||||||
methods := target.Exports()
|
|
||||||
if uint64(len(methods)) <= method || methods[method] == nil {
|
methodMeta, ok := actMeta[abi.MethodNum(method)]
|
||||||
|
if !ok {
|
||||||
return nil, fmt.Errorf("unknown method %d for actor %s", method, act)
|
return nil, fmt.Errorf("unknown method %d for actor %s", method, act)
|
||||||
}
|
}
|
||||||
|
|
||||||
f := methods[method]
|
paramObj := methodMeta.Params
|
||||||
|
|
||||||
rf := reflect.TypeOf(f)
|
|
||||||
if rf.NumIn() != 2 {
|
|
||||||
return nil, fmt.Errorf("expected referenced method to have three arguments")
|
|
||||||
}
|
|
||||||
|
|
||||||
paramObj := rf.In(1).Elem()
|
|
||||||
if paramObj.NumField() != len(args) {
|
if paramObj.NumField() != len(args) {
|
||||||
return nil, fmt.Errorf("not enough arguments given to call that method (expecting %d)", paramObj.NumField())
|
return nil, fmt.Errorf("not enough arguments given to call that method (expecting %d)", paramObj.NumField())
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,15 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
"github.com/filecoin-project/lotus/chain/events/state"
|
"github.com/filecoin-project/lotus/chain/events/state"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
cw_util "github.com/filecoin-project/lotus/cmd/lotus-chainwatch/util"
|
cw_util "github.com/filecoin-project/lotus/cmd/lotus-chainwatch/util"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
"github.com/ipfs/go-cid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Processor) setupCommonActors() error {
|
func (p *Processor) setupCommonActors() error {
|
||||||
@ -135,15 +138,15 @@ func (p Processor) storeActorAddresses(ctx context.Context, actors map[cid.Cid]A
|
|||||||
|
|
||||||
addressToID := map[address.Address]address.Address{}
|
addressToID := map[address.Address]address.Address{}
|
||||||
// HACK until genesis storage is figured out:
|
// HACK until genesis storage is figured out:
|
||||||
addressToID[builtin.SystemActorAddr] = builtin.SystemActorAddr
|
addressToID[builtin2.SystemActorAddr] = builtin2.SystemActorAddr
|
||||||
addressToID[builtin.InitActorAddr] = builtin.InitActorAddr
|
addressToID[builtin2.InitActorAddr] = builtin2.InitActorAddr
|
||||||
addressToID[builtin.RewardActorAddr] = builtin.RewardActorAddr
|
addressToID[builtin2.RewardActorAddr] = builtin2.RewardActorAddr
|
||||||
addressToID[builtin.CronActorAddr] = builtin.CronActorAddr
|
addressToID[builtin2.CronActorAddr] = builtin2.CronActorAddr
|
||||||
addressToID[builtin.StoragePowerActorAddr] = builtin.StoragePowerActorAddr
|
addressToID[builtin2.StoragePowerActorAddr] = builtin2.StoragePowerActorAddr
|
||||||
addressToID[builtin.StorageMarketActorAddr] = builtin.StorageMarketActorAddr
|
addressToID[builtin2.StorageMarketActorAddr] = builtin2.StorageMarketActorAddr
|
||||||
addressToID[builtin.VerifiedRegistryActorAddr] = builtin.VerifiedRegistryActorAddr
|
addressToID[builtin2.VerifiedRegistryActorAddr] = builtin2.VerifiedRegistryActorAddr
|
||||||
addressToID[builtin.BurntFundsActorAddr] = builtin.BurntFundsActorAddr
|
addressToID[builtin2.BurntFundsActorAddr] = builtin2.BurntFundsActorAddr
|
||||||
initActor, err := p.node.StateGetActor(ctx, builtin.InitActorAddr, types.EmptyTSK)
|
initActor, err := p.node.StateGetActor(ctx, builtin2.InitActorAddr, types.EmptyTSK)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,10 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"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"
|
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
@ -35,6 +38,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"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/actors/builtin/miner"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/tools/stats"
|
"github.com/filecoin-project/lotus/tools/stats"
|
||||||
@ -340,6 +344,18 @@ var runCmd = &cli.Command{
|
|||||||
Usage: "process ProveCommitSector messages",
|
Usage: "process ProveCommitSector messages",
|
||||||
Value: true,
|
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{
|
&cli.IntFlag{
|
||||||
Name: "head-delay",
|
Name: "head-delay",
|
||||||
EnvVars: []string{"LOTUS_PCR_HEAD_DELAY"},
|
EnvVars: []string{"LOTUS_PCR_HEAD_DELAY"},
|
||||||
@ -376,6 +392,18 @@ var runCmd = &cli.Command{
|
|||||||
Usage: "percent of refund to issue",
|
Usage: "percent of refund to issue",
|
||||||
Value: 110,
|
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.0000000001",
|
||||||
|
},
|
||||||
|
&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.0000000001",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
go func() {
|
go func() {
|
||||||
@ -419,6 +447,8 @@ var runCmd = &cli.Command{
|
|||||||
dryRun := cctx.Bool("dry-run")
|
dryRun := cctx.Bool("dry-run")
|
||||||
preCommitEnabled := cctx.Bool("pre-commit")
|
preCommitEnabled := cctx.Bool("pre-commit")
|
||||||
proveCommitEnabled := cctx.Bool("prove-commit")
|
proveCommitEnabled := cctx.Bool("prove-commit")
|
||||||
|
windowedPoStEnabled := cctx.Bool("windowed-post")
|
||||||
|
publishStorageDealsEnabled := cctx.Bool("storage-deals")
|
||||||
aggregateTipsets := cctx.Int("aggregate-tipsets")
|
aggregateTipsets := cctx.Int("aggregate-tipsets")
|
||||||
minerRecoveryEnabled := cctx.Bool("miner-recovery")
|
minerRecoveryEnabled := cctx.Bool("miner-recovery")
|
||||||
minerRecoveryPeriod := abi.ChainEpoch(int64(cctx.Int("miner-recovery-period")))
|
minerRecoveryPeriod := abi.ChainEpoch(int64(cctx.Int("miner-recovery-period")))
|
||||||
@ -426,6 +456,16 @@ var runCmd = &cli.Command{
|
|||||||
minerRecoveryCutoff := uint64(cctx.Int("miner-recovery-cutoff"))
|
minerRecoveryCutoff := uint64(cctx.Int("miner-recovery-cutoff"))
|
||||||
minerRecoveryBonus := uint64(cctx.Int("miner-recovery-bonus"))
|
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{
|
rf := &refunder{
|
||||||
api: api,
|
api: api,
|
||||||
wallet: from,
|
wallet: from,
|
||||||
@ -436,6 +476,10 @@ var runCmd = &cli.Command{
|
|||||||
dryRun: dryRun,
|
dryRun: dryRun,
|
||||||
preCommitEnabled: preCommitEnabled,
|
preCommitEnabled: preCommitEnabled,
|
||||||
proveCommitEnabled: proveCommitEnabled,
|
proveCommitEnabled: proveCommitEnabled,
|
||||||
|
windowedPoStEnabled: windowedPoStEnabled,
|
||||||
|
publishStorageDealsEnabled: publishStorageDealsEnabled,
|
||||||
|
preFeeCapMax: types.BigInt(preFeeCapMax),
|
||||||
|
proveFeeCapMax: types.BigInt(proveFeeCapMax),
|
||||||
}
|
}
|
||||||
|
|
||||||
var refunds *MinersRefund = NewMinersRefund()
|
var refunds *MinersRefund = NewMinersRefund()
|
||||||
@ -587,7 +631,12 @@ type refunder struct {
|
|||||||
dryRun bool
|
dryRun bool
|
||||||
preCommitEnabled bool
|
preCommitEnabled bool
|
||||||
proveCommitEnabled bool
|
proveCommitEnabled bool
|
||||||
|
windowedPoStEnabled bool
|
||||||
|
publishStorageDealsEnabled bool
|
||||||
threshold big.Int
|
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) {
|
func (r *refunder) FindMiners(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund, owner, worker, control bool) (*MinersRefund, error) {
|
||||||
@ -815,6 +864,147 @@ func (r *refunder) EnsureMinerMinimums(ctx context.Context, tipset *types.TipSet
|
|||||||
return refunds, nil
|
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) {
|
func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund) (*MinersRefund, error) {
|
||||||
cids := tipset.Cids()
|
cids := tipset.Cids()
|
||||||
if len(cids) == 0 {
|
if len(cids) == 0 {
|
||||||
@ -839,9 +1029,9 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
refundValue := types.NewInt(0)
|
|
||||||
tipsetRefunds := NewMinersRefund()
|
tipsetRefunds := NewMinersRefund()
|
||||||
for i, msg := range msgs {
|
for i, msg := range msgs {
|
||||||
|
refundValue := types.NewInt(0)
|
||||||
m := msg.Message
|
m := msg.Message
|
||||||
|
|
||||||
a, err := r.api.StateGetActor(ctx, m.To, tipset.Key())
|
a, err := r.api.StateGetActor(ctx, m.To, tipset.Key())
|
||||||
@ -850,91 +1040,23 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !a.IsStorageMinerActor() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var messageMethod string
|
var messageMethod string
|
||||||
|
var processed bool
|
||||||
|
|
||||||
switch m.Method {
|
if m.To == market.Address {
|
||||||
case builtin.MethodsMiner.ProveCommitSector:
|
processed, messageMethod, refundValue, err = r.processTipsetStorageMarketActor(ctx, tipset, msg, recps[i])
|
||||||
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 builtin.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 r.refundPercent > 0 {
|
if builtin.IsStorageMinerActor(a.Code) {
|
||||||
refundValue = types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.refundPercent)))
|
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(
|
log.Debugw(
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
lotusbuiltin "github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ var chainBalanceCmd = &cli.Command{
|
|||||||
Type: string(act.Code.Hash()[2:]),
|
Type: string(act.Code.Hash()[2:]),
|
||||||
}
|
}
|
||||||
|
|
||||||
if act.IsStorageMinerActor() {
|
if builtin.IsStorageMinerActor(act.Code) {
|
||||||
pow, err := api.StateMinerPower(ctx, addr, tsk)
|
pow, err := api.StateMinerPower(ctx, addr, tsk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to get power: %w", err)
|
return xerrors.Errorf("failed to get power: %w", err)
|
||||||
@ -198,7 +198,7 @@ var chainBalanceStateCmd = &cli.Command{
|
|||||||
PreCommits: types.FIL(big.NewInt(0)),
|
PreCommits: types.FIL(big.NewInt(0)),
|
||||||
}
|
}
|
||||||
|
|
||||||
if minerInfo && act.IsStorageMinerActor() {
|
if minerInfo && builtin.IsStorageMinerActor(act.Code) {
|
||||||
pow, _, _, err := stmgr.GetPowerRaw(ctx, sm, sroot, addr)
|
pow, _, _, err := stmgr.GetPowerRaw(ctx, sm, sroot, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to get power: %w", err)
|
return xerrors.Errorf("failed to get power: %w", err)
|
||||||
@ -322,7 +322,7 @@ var chainPledgeCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
powerSmoothed lotusbuiltin.FilterEstimate
|
powerSmoothed builtin.FilterEstimate
|
||||||
pledgeCollateral abi.TokenAmount
|
pledgeCollateral abi.TokenAmount
|
||||||
)
|
)
|
||||||
if act, err := state.GetActor(power.Address); err != nil {
|
if act, err := state.GetActor(power.Address); err != nil {
|
||||||
|
@ -3,8 +3,10 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/go-units"
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
dsq "github.com/ipfs/go-datastore/query"
|
dsq "github.com/ipfs/go-datastore/query"
|
||||||
logging "github.com/ipfs/go-log"
|
logging "github.com/ipfs/go-log"
|
||||||
@ -12,6 +14,7 @@ import (
|
|||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/lib/backupds"
|
||||||
"github.com/filecoin-project/lotus/node/repo"
|
"github.com/filecoin-project/lotus/node/repo"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,6 +22,7 @@ var datastoreCmd = &cli.Command{
|
|||||||
Name: "datastore",
|
Name: "datastore",
|
||||||
Description: "access node datastores directly",
|
Description: "access node datastores directly",
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
|
datastoreBackupCmd,
|
||||||
datastoreListCmd,
|
datastoreListCmd,
|
||||||
datastoreGetCmd,
|
datastoreGetCmd,
|
||||||
},
|
},
|
||||||
@ -30,6 +34,7 @@ var datastoreListCmd = &cli.Command{
|
|||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
Name: "repo-type",
|
Name: "repo-type",
|
||||||
|
Usage: "node type (1 - full, 2 - storage, 3 - worker)",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
@ -43,7 +48,7 @@ var datastoreListCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
ArgsUsage: "[namespace prefix]",
|
ArgsUsage: "[namespace prefix]",
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
logging.SetLogLevel("badger", "ERROR") // nolint:errchec
|
logging.SetLogLevel("badger", "ERROR") // nolint:errcheck
|
||||||
|
|
||||||
r, err := repo.NewFS(cctx.String("repo"))
|
r, err := repo.NewFS(cctx.String("repo"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -80,33 +85,11 @@ var datastoreListCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
defer q.Close() //nolint:errcheck
|
defer q.Close() //nolint:errcheck
|
||||||
|
|
||||||
seen := map[string]struct{}{}
|
printKv := kvPrinter(cctx.Bool("top-level"), genc)
|
||||||
|
|
||||||
for res := range q.Next() {
|
for res := range q.Next() {
|
||||||
s := res.Key
|
if err := printKv(res.Key, res.Value); err != nil {
|
||||||
if cctx.Bool("top-level") {
|
return err
|
||||||
k := datastore.NewKey(datastore.NewKey(s).List()[0])
|
|
||||||
if k.Type() != "" {
|
|
||||||
s = k.Type()
|
|
||||||
} else {
|
|
||||||
s = k.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
_, has := seen[s]
|
|
||||||
if has {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
seen[s] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
s = fmt.Sprintf("%q", s)
|
|
||||||
s = strings.Trim(s, "\"")
|
|
||||||
fmt.Println(s)
|
|
||||||
|
|
||||||
if genc != "" {
|
|
||||||
fmt.Print("\t")
|
|
||||||
if err := printVal(genc, res.Value); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +103,7 @@ var datastoreGetCmd = &cli.Command{
|
|||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
Name: "repo-type",
|
Name: "repo-type",
|
||||||
|
Usage: "node type (1 - full, 2 - storage, 3 - worker)",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
@ -165,6 +149,120 @@ var datastoreGetCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var datastoreBackupCmd = &cli.Command{
|
||||||
|
Name: "backup",
|
||||||
|
Description: "manage datastore backups",
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
datastoreBackupStatCmd,
|
||||||
|
datastoreBackupListCmd,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var datastoreBackupStatCmd = &cli.Command{
|
||||||
|
Name: "stat",
|
||||||
|
Description: "validate and print info about datastore backup",
|
||||||
|
ArgsUsage: "[file]",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if cctx.Args().Len() != 1 {
|
||||||
|
return xerrors.Errorf("expected 1 argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(cctx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("opening backup file: %w", err)
|
||||||
|
}
|
||||||
|
defer f.Close() // nolint:errcheck
|
||||||
|
|
||||||
|
var keys, kbytes, vbytes uint64
|
||||||
|
err = backupds.ReadBackup(f, func(key datastore.Key, value []byte) error {
|
||||||
|
keys++
|
||||||
|
kbytes += uint64(len(key.String()))
|
||||||
|
vbytes += uint64(len(value))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Keys: ", keys)
|
||||||
|
fmt.Println("Key bytes: ", units.BytesSize(float64(kbytes)))
|
||||||
|
fmt.Println("Value bytes: ", units.BytesSize(float64(vbytes)))
|
||||||
|
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var datastoreBackupListCmd = &cli.Command{
|
||||||
|
Name: "list",
|
||||||
|
Description: "list data in a backup",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "top-level",
|
||||||
|
Usage: "only print top-level keys",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "get-enc",
|
||||||
|
Usage: "print values [esc/hex/cbor]",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ArgsUsage: "[file]",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if cctx.Args().Len() != 1 {
|
||||||
|
return xerrors.Errorf("expected 1 argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(cctx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("opening backup file: %w", err)
|
||||||
|
}
|
||||||
|
defer f.Close() // nolint:errcheck
|
||||||
|
|
||||||
|
printKv := kvPrinter(cctx.Bool("top-level"), cctx.String("get-enc"))
|
||||||
|
err = backupds.ReadBackup(f, func(key datastore.Key, value []byte) error {
|
||||||
|
return printKv(key.String(), value)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func kvPrinter(toplevel bool, genc string) func(sk string, value []byte) error {
|
||||||
|
seen := map[string]struct{}{}
|
||||||
|
|
||||||
|
return func(s string, value []byte) error {
|
||||||
|
if toplevel {
|
||||||
|
k := datastore.NewKey(datastore.NewKey(s).List()[0])
|
||||||
|
if k.Type() != "" {
|
||||||
|
s = k.Type()
|
||||||
|
} else {
|
||||||
|
s = k.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
_, has := seen[s]
|
||||||
|
if has {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
seen[s] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
s = fmt.Sprintf("%q", s)
|
||||||
|
s = strings.Trim(s, "\"")
|
||||||
|
fmt.Println(s)
|
||||||
|
|
||||||
|
if genc != "" {
|
||||||
|
fmt.Print("\t")
|
||||||
|
if err := printVal(genc, value); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func printVal(enc string, val []byte) error {
|
func printVal(enc string, val []byte) error {
|
||||||
switch enc {
|
switch enc {
|
||||||
case "esc":
|
case "esc":
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
@ -95,14 +97,14 @@ var genesisVerifyCmd = &cli.Command{
|
|||||||
|
|
||||||
if err := stree.ForEach(func(addr address.Address, act *types.Actor) error {
|
if err := stree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||||
switch {
|
switch {
|
||||||
case act.IsStorageMinerActor():
|
case builtin.IsStorageMinerActor(act.Code):
|
||||||
_, err := miner.Load(store, act)
|
_, err := miner.Load(store, act)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("miner actor: %w", err)
|
return xerrors.Errorf("miner actor: %w", err)
|
||||||
}
|
}
|
||||||
// TODO: actually verify something here?
|
// TODO: actually verify something here?
|
||||||
kminers[addr] = minerInfo{}
|
kminers[addr] = minerInfo{}
|
||||||
case act.IsMultisigActor():
|
case builtin.IsMultisigActor(act.Code):
|
||||||
st, err := multisig.Load(store, act)
|
st, err := multisig.Load(store, act)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("multisig actor: %w", err)
|
return xerrors.Errorf("multisig actor: %w", err)
|
||||||
@ -123,7 +125,7 @@ var genesisVerifyCmd = &cli.Command{
|
|||||||
Threshold: threshold,
|
Threshold: threshold,
|
||||||
}
|
}
|
||||||
msigAddrs = append(msigAddrs, addr)
|
msigAddrs = append(msigAddrs, addr)
|
||||||
case act.IsAccountActor():
|
case builtin.IsAccountActor(act.Code):
|
||||||
st, err := account.Load(store, act)
|
st, err := account.Load(store, act)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: magik6k: this _used_ to log instead of failing, why?
|
// TODO: magik6k: this _used_ to log instead of failing, why?
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
lapi "github.com/filecoin-project/lotus/api"
|
lapi "github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
lcli "github.com/filecoin-project/lotus/cli"
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
)
|
)
|
||||||
@ -122,7 +123,7 @@ var mpoolStatsCmd = &cli.Command{
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ism := act.IsStorageMinerActor()
|
ism := builtin.IsStorageMinerActor(act.Code)
|
||||||
mcache[addr] = ism
|
mcache[addr] = ism
|
||||||
return ism, nil
|
return ism, nil
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user