Compare commits

..
Author SHA1 Message Date
Aayush Rajasekaran 304d835739 Merge branch 'master' into next 2020-10-07 23:03:59 -04:00
Łukasz Magiera cb8678e4c2 Merge pull request #4235 from filecoin-project/asr/set-head-unmark-valid
Set head should unmark blocks as valid
2020-10-08 03:58:05 +02:00
Aayush Rajasekaran da34548a05 Set head should unmark blocks as valid 2020-10-07 21:52:29 -04:00
Łukasz Magiera b1fe92f8ff Merge pull request #4201 from filecoin-project/feat/faster-v2-upgrade
stmgr: Make v2 upgrade faster
2020-10-08 01:56:05 +02:00
Łukasz Magiera 8dd8892b81 Merge remote-tracking branch 'origin/next' into feat/faster-v2-upgrade 2020-10-08 01:54:29 +02:00
Łukasz Magiera 79dba816c7 Merge pull request #4232 from filecoin-project/steb/fix-v2-actor-error
return an illegal actor error when we see an unsupported actor version
2020-10-08 01:47:10 +02:00
Aayush Rajasekaran 14bb4c9a0b Merge pull request #4196 from filecoin-project/asr/update-epoch
Set actorsv2 upgrade epoch
2020-10-07 19:45:56 -04:00
Łukasz Magiera f9f54819d4 Env var to control v2 actor migration
Env var to control v2 actor migration
2020-10-07 19:41:36 -04:00
Aayush Rajasekaran d1555106a4 Set actorsv2 upgrade epoch 2020-10-07 19:41:36 -04:00
Steven Allen 413c357361 Merge pull request #4231 from filecoin-project/steb/call-at-upgrade
reject explicit "calls" at the upgrade height
2020-10-07 16:33:51 -07:00
Steven Allen d97eb10349 fix spelling nit 2020-10-07 16:32:54 -07:00
Steven Allen e8253d22c6 only forbid Call* at expensive forks 2020-10-07 16:14:11 -07:00
Steven Allen a4e954197c retry StateCall at different height if we're at an expensive fork height 2020-10-07 16:03:42 -07:00
Steven Allen b0bea5f145 return an illegal actor error when we see an unsupported actor version
As far as the chain is concerned, this actor does not exist.
2020-10-07 15:46:56 -07:00
Travis Person 7c7e0d73d5 Merge pull request #4229 from filecoin-project/fix/lotus-pcr-zero-refund
lotus-pcr: zero refund
2020-10-07 15:33:28 -07:00
Steven Allen 1fea550ce5 test that we refuse explicit calls at the migration epochs 2020-10-07 15:33:14 -07:00
Steven Allen 9b7b6146eb construct the new vm with the state manager's vm constructor 2020-10-07 15:31:14 -07:00
Steven Allen dab1107f5b avoid estimating gas and explicitly calling blocks on fork tipsets
These tipsets can be slow.
2020-10-07 15:31:14 -07:00
Steven Allen fe912223bd pass an explicit upgrade height to migrations
The tipset height may not be the correct one, given null blocks.
2020-10-07 15:31:12 -07:00
Travis Person ae3691e0a2 lotus-pcr: zero refund 2020-10-07 21:53:56 +00:00
Steven Allen de3f4111f4 Merge pull request #4197 from filecoin-project/steb/state-tree-version
introduce separate state-tree versions
2020-10-07 12:29:14 -07:00
Steven Allen 767c346cf8 update test-vectors 2020-10-07 12:17:32 -07:00
Steven Allen cca17f6078 fix state tree version in v2 upgrade 2020-10-07 12:04:32 -07:00
Steven Allen c17fa4bc35 update test-vectors for StateManager constructor change 2020-10-07 12:04:32 -07:00
Steven Allen e803cf151f introduce separate state-tree versions
Instead of versioning the state tree along with the actors, version it
separately. This structure may not upgrade every time we update actors.
2020-10-07 12:04:32 -07:00
Łukasz Magiera 1268cfbfcd Merge pull request #4218 from filecoin-project/fix/lotus-pcr-ignore-other-messages
lotus-pcr: ignore all other messages
2020-10-07 21:03:53 +02:00
Łukasz Magiera 5ef929f130 Merge pull request #4219 from filecoin-project/merge-master-to-next
Merge branch 'master' into merge-master-to-next
2020-10-07 21:02:57 +02:00
Steven Allen df4b068d0e Merge branch 'master' into next 2020-10-07 11:55:00 -07:00
Travis Person 0d34881a0c lotus-pcr: ignore all other messages 2020-10-07 18:50:50 +00:00
Steven Allen 6eb49b717f Merge pull request #4214 from filecoin-project/gas-tracing-public
make vm.EnableGasTracing public.
2020-10-07 11:12:55 -07:00
Whyrusleeping 099b982ea8 Merge pull request #4178 from filecoin-project/frrist/miner-diff-deadlines
feat(miner): add miner deadline diffing logic.
2020-10-07 12:00:31 -05:00
Łukasz Magiera 10c120bd3c Merge pull request #4213 from filecoin-project/feat/test-addrs-envvar
build: Env var to keep test address output
2020-10-07 18:49:55 +02:00
Raúl Kripalani 7cd1330acd make vm.EnableGasTracing public. 2020-10-07 15:52:03 +01:00
Łukasz Magiera 39bc816a79 build: Env var to keep test address output 2020-10-07 15:01:30 +02:00
Łukasz Magiera 81fb552e1d Merge pull request #4211 from filecoin-project/conformance/minor-refactors
conformance: minor driver refactors.
2020-10-07 14:57:00 +02:00
Łukasz Magiera cfd126ee9f Merge pull request #3961 from filecoin-project/docs/miner-storage
lotus-miner: add more help text to storage / attach
2020-10-07 14:55:42 +02:00
Łukasz Magiera d6fa644974 Fix lint 2020-10-07 14:19:04 +02:00
Raúl Kripalani d3dc560f53 conformance: minor refactors. 2020-10-07 13:01:08 +01:00
Łukasz Magiera 25bc00eec8 Merge pull request #4200 from filecoin-project/feat/state-exec-trace
implement command to get execution traces of any message
2020-10-07 08:14:08 +02:00
whyrusleeping 3b12a9f425 Add flag to accept previous output of compute-state as input 2020-10-07 08:12:39 +02:00
Łukasz Magiera b7c8f65af5 stmgr: Make v2 upgrade faster 2020-10-07 08:12:05 +02:00
Łukasz Magiera c6e0cb4ff2 Merge pull request #4205 from filecoin-project/feat/noncefix-manual-fee-cap
allow manual setting of noncefix fee cap
2020-10-07 08:08:52 +02:00
Łukasz Magiera f6eb530cba Merge pull request #4203 from filecoin-project/fix/pond-actorsv2
Fix pond
2020-10-07 07:55:38 +02:00
Travis Person f4991e868e Merge pull request #4198 from filecoin-project/feat/lotus-pcr-cap-limit
Limit the fee cap of messages we will process, refund gas fees for windowed post and storage deals
2020-10-06 21:03:43 -07:00
whyrusleeping be92dd9e63 allow manual setting of noncefix fee cap 2020-10-06 18:07:34 -07:00
Łukasz Magiera 15670942c3 Fix pond 2020-10-07 01:50:11 +02:00
whyrusleeping bd474617ed implement command to get execution traces of any message 2020-10-06 16:06:24 -07:00
Travis Person 087030fe37 lotus-pcr: refund windowed post and storage deal gas fees 2020-10-06 22:35:04 +00:00
Travis Person 4a3081c77a lotus-pcr: limit refunds to properly priced messages 2020-10-06 20:13:48 +00:00
frrist d4cbd4fb55 feat(miner): add miner deadline diffing
- logic gathering all removed, faulted, recovered, and recovering
sectors for a miner.
2020-10-06 11:39:38 -07:00
Łukasz Magiera 1fc23fb466 lotus-miner: Cleanup storage attach helptext a bit 2020-10-03 11:30:22 +02:00
Travis Person c66f087f4c lotus-miner: add more help text to storage / attach 2020-09-22 18:15:42 +00:00
40 changed files with 1094 additions and 253 deletions
+12 -4
View File
@@ -1,4 +1,12 @@
/dns4/bootstrap-0.calibration.fildev.network/tcp/1347/p2p/12D3KooWGru4fBMc12t4rcwp9UxRAK1o8JBLdAJNL1fdYpQuu6mg
/dns4/bootstrap-1.calibration.fildev.network/tcp/1347/p2p/12D3KooWCaXUxN1cSjfS3SYM93Tv1itnUExXkohRzct1bAtjSEJ2
/dns4/bootstrap-2.calibration.fildev.network/tcp/1347/p2p/12D3KooWSdjKZoigrDK7Qkpbmk5Pk1X7c6M2YB8gjN4qEXW79cp7
/dns4/bootstrap-3.calibration.fildev.network/tcp/1347/p2p/12D3KooWR21sXfgX7MEQZEwdtPL1RwRAormMiYL1zo2h7Gmg4Tit
/dns4/bootstrap-0.testnet.fildev.network/tcp/1347/p2p/12D3KooWJTUBUjtzWJGWU1XSiY21CwmHaCNLNYn2E7jqHEHyZaP7
/dns4/bootstrap-1.testnet.fildev.network/tcp/1347/p2p/12D3KooW9yeKXha4hdrJKq74zEo99T8DhriQdWNoojWnnQbsgB3v
/dns4/bootstrap-2.testnet.fildev.network/tcp/1347/p2p/12D3KooWCrx8yVG9U9Kf7w8KLN3Edkj5ZKDhgCaeMqQbcQUoB6CT
/dns4/bootstrap-4.testnet.fildev.network/tcp/1347/p2p/12D3KooWPkL9LrKRQgHtq7kn9ecNhGU9QaziG8R5tX8v9v7t3h34
/dns4/bootstrap-3.testnet.fildev.network/tcp/1347/p2p/12D3KooWKYSsbpgZ3HAjax5M1BXCwXLa6gVkUARciz7uN3FNtr7T
/dns4/bootstrap-5.testnet.fildev.network/tcp/1347/p2p/12D3KooWQYzqnLASJAabyMpPb1GcWZvNSe7JDcRuhdRqonFoiK9W
/dns4/lotus-bootstrap.forceup.cn/tcp/41778/p2p/12D3KooWFQsv3nRMUevZNWWsY1Wu6NUzUbawnWU5NcRhgKuJA37C
/dns4/bootstrap-0.starpool.in/tcp/12757/p2p/12D3KooWGHpBMeZbestVEWkfdnC9u7p6uFHXL1n7m1ZBqsEmiUzz
/dns4/bootstrap-1.starpool.in/tcp/12757/p2p/12D3KooWQZrGH1PxSNZPum99M1zNvjNFM33d1AAu5DcvdHptuU7u
/dns4/node.glif.io/tcp/1235/p2p/12D3KooWBF8cpp65hp2u9LK5mh19x67ftAam84z9LsfaquTDSBpt
/dns4/bootstrap-0.ipfsmain.cn/tcp/34721/p2p/12D3KooWQnwEGNqcM2nAcPtRR9rAX8Hrg4k9kJLCHoTR5chJfz6d
/dns4/bootstrap-1.ipfsmain.cn/tcp/34723/p2p/12D3KooWMKxMkD5DMpSWsW7dBddKxKT7L2GgbNuckz9otxvkvByP
Binary file not shown.
+12 -2
View File
@@ -3,6 +3,9 @@
package build
import (
"math"
"os"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/chain/actors/policy"
@@ -13,8 +16,10 @@ const BreezeGasTampingDuration = 0
const UpgradeSmokeHeight = -1
const UpgradeIgnitionHeight = -2
const UpgradeLiftoffHeight = -3
const UpgradeActorsV2Height = 10
const UpgradeRefuelHeight = -3
var UpgradeActorsV2Height = abi.ChainEpoch(10)
var UpgradeLiftoffHeight = abi.ChainEpoch(-4)
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
@@ -25,6 +30,11 @@ func init() {
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
if os.Getenv("LOTUS_DISABLE_V2_ACTOR_MIGRATION") == "1" {
UpgradeActorsV2Height = math.MaxInt64
UpgradeLiftoffHeight = 11
}
BuildType |= Build2k
}
+2 -1
View File
@@ -82,8 +82,9 @@ var (
UpgradeSmokeHeight abi.ChainEpoch = -1
UpgradeIgnitionHeight abi.ChainEpoch = -2
UpgradeLiftoffHeight abi.ChainEpoch = -3
UpgradeRefuelHeight abi.ChainEpoch = -3
UpgradeActorsV2Height abi.ChainEpoch = 10
UpgradeLiftoffHeight abi.ChainEpoch = -4
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
+19 -9
View File
@@ -5,6 +5,9 @@
package build
import (
"math"
"os"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/chain/actors/policy"
@@ -13,17 +16,19 @@ import (
)
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
0: DrandIncentinet,
UpgradeSmokeHeight: DrandMainnet,
}
const UpgradeBreezeHeight = -1
const UpgradeBreezeHeight = 41280
const BreezeGasTampingDuration = 120
const UpgradeSmokeHeight = -2
const UpgradeSmokeHeight = 51000
const UpgradeIgnitionHeight = -3
const UpgradeIgnitionHeight = 94000
const UpgradeRefuelHeight = 130800
const UpgradeActorsV2Height = 500
var UpgradeActorsV2Height = abi.ChainEpoch(138720)
// This signals our tentative epoch for mainnet launch. Can make it later, but not earlier.
// Miners, clients, developers, custodians all need time to prepare.
@@ -31,16 +36,21 @@ const UpgradeActorsV2Height = 500
const UpgradeLiftoffHeight = 148888
func init() {
policy.SetConsensusMinerMinPower(abi.NewStoragePower(10 << 30))
policy.SetConsensusMinerMinPower(abi.NewStoragePower(10 << 40))
policy.SetSupportedProofTypes(
abi.RegisteredSealProof_StackedDrg512MiBV1,
abi.RegisteredSealProof_StackedDrg32GiBV1,
abi.RegisteredSealProof_StackedDrg64GiBV1,
)
SetAddressNetwork(address.Testnet)
if os.Getenv("LOTUS_USE_TEST_ADDRESSES") != "1" {
SetAddressNetwork(address.Mainnet)
}
Devnet = true
if os.Getenv("LOTUS_DISABLE_V2_ACTOR_MIGRATION") == "1" {
UpgradeActorsV2Height = math.MaxInt64
}
Devnet = false
}
const BlockDelaySecs = uint64(builtin0.EpochDurationSeconds)
+1
View File
@@ -22,6 +22,7 @@ import (
var SystemActorAddr = builtin0.SystemActorAddr
var BurntFundsActorAddr = builtin0.BurntFundsActorAddr
var ReserveAddress = makeAddress("t090")
var RootVerifierAddress = makeAddress("t080")
// TODO: Why does actors have 2 different versions of this?
type SectorInfo = proof0.SectorInfo
@@ -0,0 +1,180 @@
package miner
import (
"errors"
"github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/go-state-types/exitcode"
)
type DeadlinesDiff map[uint64]*DeadlineDiff
func DiffDeadlines(pre, cur State) (*DeadlinesDiff, error) {
changed, err := pre.DeadlinesChanged(cur)
if err != nil {
return nil, err
}
if !changed {
return nil, nil
}
numDl, err := pre.NumDeadlines()
if err != nil {
return nil, err
}
dlDiff := make(DeadlinesDiff, numDl)
if err := pre.ForEachDeadline(func(idx uint64, preDl Deadline) error {
curDl, err := cur.LoadDeadline(idx)
if err != nil {
return err
}
diff, err := DiffDeadline(preDl, curDl)
if err != nil {
return err
}
dlDiff[idx] = diff
return nil
}); err != nil {
return nil, err
}
return &dlDiff, nil
}
type DeadlineDiff map[uint64]*PartitionDiff
func DiffDeadline(pre, cur Deadline) (*DeadlineDiff, error) {
changed, err := pre.PartitionsChanged(cur)
if err != nil {
return nil, err
}
if !changed {
return nil, nil
}
partDiff := make(DeadlineDiff)
if err := pre.ForEachPartition(func(idx uint64, prePart Partition) error {
// try loading current partition at this index
curPart, err := cur.LoadPartition(idx)
if err != nil {
if errors.Is(err, exitcode.ErrNotFound) {
// TODO correctness?
return nil // the partition was removed.
}
return err
}
// compare it with the previous partition
diff, err := DiffPartition(prePart, curPart)
if err != nil {
return err
}
partDiff[idx] = diff
return nil
}); err != nil {
return nil, err
}
// all previous partitions have been walked.
// all partitions in cur and not in prev are new... can they be faulty already?
// TODO is this correct?
if err := cur.ForEachPartition(func(idx uint64, curPart Partition) error {
if _, found := partDiff[idx]; found {
return nil
}
faults, err := curPart.FaultySectors()
if err != nil {
return err
}
recovering, err := curPart.RecoveringSectors()
if err != nil {
return err
}
partDiff[idx] = &PartitionDiff{
Removed: bitfield.New(),
Recovered: bitfield.New(),
Faulted: faults,
Recovering: recovering,
}
return nil
}); err != nil {
return nil, err
}
return &partDiff, nil
}
type PartitionDiff struct {
Removed bitfield.BitField
Recovered bitfield.BitField
Faulted bitfield.BitField
Recovering bitfield.BitField
}
func DiffPartition(pre, cur Partition) (*PartitionDiff, error) {
prevLiveSectors, err := pre.LiveSectors()
if err != nil {
return nil, err
}
curLiveSectors, err := cur.LiveSectors()
if err != nil {
return nil, err
}
removed, err := bitfield.SubtractBitField(prevLiveSectors, curLiveSectors)
if err != nil {
return nil, err
}
prevRecoveries, err := pre.RecoveringSectors()
if err != nil {
return nil, err
}
curRecoveries, err := cur.RecoveringSectors()
if err != nil {
return nil, err
}
recovering, err := bitfield.SubtractBitField(curRecoveries, prevRecoveries)
if err != nil {
return nil, err
}
prevFaults, err := pre.FaultySectors()
if err != nil {
return nil, err
}
curFaults, err := cur.FaultySectors()
if err != nil {
return nil, err
}
faulted, err := bitfield.SubtractBitField(curFaults, prevFaults)
if err != nil {
return nil, err
}
// all current good sectors
curActiveSectors, err := cur.ActiveSectors()
if err != nil {
return nil, err
}
// sectors that were previously fault and are now currently active are considered recovered.
recovered, err := bitfield.IntersectBitField(prevFaults, curActiveSectors)
if err != nil {
return nil, err
}
return &PartitionDiff{
Removed: removed,
Recovered: recovered,
Faulted: faulted,
Recovering: recovering,
}, nil
}
+2 -2
View File
@@ -9,8 +9,8 @@ import (
type Version int
const (
Version0 = 0
Version2 = 2
Version0 Version = 0
Version2 Version = 2
)
// Converts a network version into an actors adt version.
+1 -2
View File
@@ -26,7 +26,6 @@ import (
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
@@ -117,7 +116,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
return nil, nil, xerrors.Errorf("putting empty object: %w", err)
}
state, err := state.NewStateTree(cst, actors.Version0)
state, err := state.NewStateTree(cst, types.StateTreeVersion0)
if err != nil {
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
}
+40 -16
View File
@@ -13,6 +13,7 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/chain/actors"
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
cbg "github.com/whyrusleeping/cbor-gen"
@@ -26,7 +27,7 @@ var log = logging.Logger("statetree")
// StateTree stores actors state by their ID.
type StateTree struct {
root adt.Map
version actors.Version // TODO
version types.StateTreeVersion
info cid.Cid
Store cbor.IpldStore
@@ -120,21 +121,41 @@ func (ss *stateSnaps) deleteActor(addr address.Address) {
ss.layers[len(ss.layers)-1].actors[addr] = streeOp{Delete: true}
}
func NewStateTree(cst cbor.IpldStore, version actors.Version) (*StateTree, error) {
// VersionForNetwork returns the state tree version for the given network
// version.
func VersionForNetwork(ver network.Version) types.StateTreeVersion {
if actors.VersionForNetwork(ver) == actors.Version0 {
return types.StateTreeVersion0
}
return types.StateTreeVersion1
}
func adtForSTVersion(ver types.StateTreeVersion) actors.Version {
switch ver {
case types.StateTreeVersion0:
return actors.Version0
case types.StateTreeVersion1:
return actors.Version2
default:
panic("unhandled state tree version")
}
}
func NewStateTree(cst cbor.IpldStore, ver types.StateTreeVersion) (*StateTree, error) {
var info cid.Cid
switch version {
case actors.Version0:
switch ver {
case types.StateTreeVersion0:
// info is undefined
case actors.Version2:
case types.StateTreeVersion1:
var err error
info, err = cst.Put(context.TODO(), new(types.StateInfo))
info, err = cst.Put(context.TODO(), new(types.StateInfo0))
if err != nil {
return nil, err
}
default:
return nil, xerrors.Errorf("unsupported state tree version: %d", version)
return nil, xerrors.Errorf("unsupported state tree version: %d", ver)
}
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), version)
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), adtForSTVersion(ver))
if err != nil {
return nil, err
}
@@ -142,7 +163,7 @@ func NewStateTree(cst cbor.IpldStore, version actors.Version) (*StateTree, error
return &StateTree{
root: root,
info: info,
version: version,
version: ver,
Store: cst,
snaps: newStateSnaps(),
}, nil
@@ -154,13 +175,16 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
if err := cst.Get(context.TODO(), c, &root); err != nil {
// We failed to decode as the new version, must be an old version.
root.Actors = c
root.Version = actors.Version0
root.Version = types.StateTreeVersion0
}
switch root.Version {
case actors.Version0, actors.Version2:
case types.StateTreeVersion0, types.StateTreeVersion1:
// Load the actual state-tree HAMT.
nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), root.Actors, actors.Version(root.Version))
nd, err := adt.AsMap(
adt.WrapStore(context.TODO(), cst), root.Actors,
adtForSTVersion(root.Version),
)
if err != nil {
log.Errorf("loading hamt node %s failed: %s", c, err)
return nil, err
@@ -169,7 +193,7 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
return &StateTree{
root: nd,
info: root.Info,
version: actors.Version(root.Version),
version: root.Version,
Store: cst,
snaps: newStateSnaps(),
}, nil
@@ -309,11 +333,11 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
return cid.Undef, xerrors.Errorf("failed to flush state-tree hamt: %w", err)
}
// If we're version 0, return a raw tree.
if st.version == actors.Version0 {
if st.version == types.StateTreeVersion0 {
return root, nil
}
// Otherwise, return a versioned tree.
return st.Store.Put(ctx, &types.StateRoot{Version: uint64(st.version), Actors: root, Info: st.info})
return st.Store.Put(ctx, &types.StateRoot{Version: st.version, Actors: root, Info: st.info})
}
func (st *StateTree) Snapshot(ctx context.Context) error {
@@ -400,7 +424,7 @@ func (st *StateTree) ForEach(f func(address.Address, *types.Actor) error) error
}
// Version returns the version of the StateTree data structure in use.
func (st *StateTree) Version() actors.Version {
func (st *StateTree) Version() types.StateTreeVersion {
return st.version
}
+6 -7
View File
@@ -13,13 +13,12 @@ import (
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
)
func BenchmarkStateTreeSet(b *testing.B) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
b.Fatal(err)
}
@@ -46,7 +45,7 @@ func BenchmarkStateTreeSet(b *testing.B) {
func BenchmarkStateTreeSetFlush(b *testing.B) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
b.Fatal(err)
}
@@ -76,7 +75,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) {
func BenchmarkStateTree10kGetActor(b *testing.B) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
b.Fatal(err)
}
@@ -118,7 +117,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) {
func TestSetCache(t *testing.T) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
t.Fatal(err)
}
@@ -155,7 +154,7 @@ func TestSetCache(t *testing.T) {
func TestSnapshots(t *testing.T) {
ctx := context.Background()
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
t.Fatal(err)
}
@@ -239,7 +238,7 @@ func assertNotHas(t *testing.T, st *StateTree, addr address.Address) {
func TestStateTreeConsistency(t *testing.T) {
cst := cbor.NewMemCborStore()
// TODO: ActorUpgrade: this test tests pre actors v2
st, err := NewStateTree(cst, actors.VersionForNetwork(network.Version3))
st, err := NewStateTree(cst, VersionForNetwork(network.Version3))
if err != nil {
t.Fatal(err)
}
+42 -2
View File
@@ -2,6 +2,7 @@ package stmgr
import (
"context"
"errors"
"fmt"
"github.com/filecoin-project/go-address"
@@ -17,17 +18,38 @@ import (
"github.com/filecoin-project/lotus/chain/vm"
)
var ErrExpensiveFork = errors.New("refusing explicit call due to state fork at epoch")
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) {
ctx, span := trace.StartSpan(ctx, "statemanager.Call")
defer span.End()
// If no tipset is provided, try to find one without a fork.
if ts == nil {
ts = sm.cs.GetHeaviestTipSet()
// Search back till we find a height with no fork, or we reach the beginning.
for ts.Height() > 0 && sm.hasExpensiveFork(ctx, ts.Height()-1) {
var err error
ts, err = sm.cs.GetTipSetFromKey(ts.Parents())
if err != nil {
return nil, xerrors.Errorf("failed to find a non-forking epoch: %w", err)
}
}
}
bstate := ts.ParentState()
bheight := ts.Height()
// If we have to run an expensive migration, and we're not at genesis,
// return an error because the migration will take too long.
//
// We allow this at height 0 for at-genesis migrations (for testing).
if bheight-1 > 0 && sm.hasExpensiveFork(ctx, bheight-1) {
return nil, ErrExpensiveFork
}
// Run the (not expensive) migration.
bstate, err := sm.handleStateForks(ctx, bstate, bheight-1, nil, ts)
if err != nil {
return nil, fmt.Errorf("failed to handle fork: %w", err)
@@ -44,7 +66,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
BaseFee: types.NewInt(0),
}
vmi, err := vm.NewVM(ctx, vmopt)
vmi, err := sm.newVM(ctx, vmopt)
if err != nil {
return nil, xerrors.Errorf("failed to set up vm: %w", err)
}
@@ -106,6 +128,24 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
if ts == nil {
ts = sm.cs.GetHeaviestTipSet()
// Search back till we find a height with no fork, or we reach the beginning.
// We need the _previous_ height to have no fork, because we'll
// run the fork logic in `sm.TipSetState`. We need the _current_
// height to have no fork, because we'll run it inside this
// function before executing the given message.
for ts.Height() > 0 && (sm.hasExpensiveFork(ctx, ts.Height()) || sm.hasExpensiveFork(ctx, ts.Height()-1)) {
var err error
ts, err = sm.cs.GetTipSetFromKey(ts.Parents())
if err != nil {
return nil, xerrors.Errorf("failed to find a non-forking epoch: %w", err)
}
}
}
// When we're not at the genesis block, make sure we don't have an expensive migration.
if ts.Height() > 0 && (sm.hasExpensiveFork(ctx, ts.Height()) || sm.hasExpensiveFork(ctx, ts.Height()-1)) {
return nil, ErrExpensiveFork
}
state, _, err := sm.TipSetState(ctx, ts)
@@ -138,7 +178,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
NtwkVersion: sm.GetNtwkVersion,
BaseFee: ts.Blocks()[0].ParentBaseFee,
}
vmi, err := vm.NewVM(ctx, vmopt)
vmi, err := sm.newVM(ctx, vmopt)
if err != nil {
return nil, xerrors.Errorf("failed to set up vm: %w", err)
}
+131 -15
View File
@@ -6,6 +6,8 @@ import (
"encoding/binary"
"math"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
@@ -25,20 +27,30 @@ import (
states2 "github.com/filecoin-project/specs-actors/v2/actors/states"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/adt"
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
bstore "github.com/filecoin-project/lotus/lib/blockstore"
"github.com/filecoin-project/lotus/lib/bufbstore"
)
type UpgradeFunc func(context.Context, *StateManager, ExecCallback, cid.Cid, *types.TipSet) (cid.Cid, error)
// UpgradeFunc is a migration function run at every upgrade.
//
// - The oldState is the state produced by the upgrade epoch.
// - The returned newState is the new state that will be used by the next epoch.
// - The height is the upgrade epoch height (already executed).
// - The tipset is the tipset for the last non-null block before the upgrade. Do
// not assume that ts.Height() is the upgrade height.
type UpgradeFunc func(ctx context.Context, sm *StateManager, cb ExecCallback, oldState cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (newState cid.Cid, err error)
type Upgrade struct {
Height abi.ChainEpoch
Network network.Version
Expensive bool
Migration UpgradeFunc
}
@@ -47,7 +59,7 @@ type UpgradeSchedule []Upgrade
func DefaultUpgradeSchedule() UpgradeSchedule {
var us UpgradeSchedule
for _, u := range []Upgrade{{
updates := []Upgrade{{
Height: build.UpgradeBreezeHeight,
Network: network.Version1,
Migration: UpgradeFaucetBurnRecovery,
@@ -59,15 +71,46 @@ func DefaultUpgradeSchedule() UpgradeSchedule {
Height: build.UpgradeIgnitionHeight,
Network: network.Version3,
Migration: UpgradeIgnition,
}, {
Height: build.UpgradeRefuelHeight,
Network: network.Version3,
Migration: UpgradeRefuel,
}, {
Height: build.UpgradeActorsV2Height,
Network: network.Version4,
Expensive: true,
Migration: UpgradeActorsV2,
}, {
Height: build.UpgradeLiftoffHeight,
Network: network.Version4,
Migration: UpgradeLiftoff,
}} {
}}
if build.UpgradeActorsV2Height == math.MaxInt64 { // disable actors upgrade
updates = []Upgrade{{
Height: build.UpgradeBreezeHeight,
Network: network.Version1,
Migration: UpgradeFaucetBurnRecovery,
}, {
Height: build.UpgradeSmokeHeight,
Network: network.Version2,
Migration: nil,
}, {
Height: build.UpgradeIgnitionHeight,
Network: network.Version3,
Migration: UpgradeIgnition,
}, {
Height: build.UpgradeRefuelHeight,
Network: network.Version3,
Migration: UpgradeRefuel,
}, {
Height: build.UpgradeLiftoffHeight,
Network: network.Version3,
Migration: UpgradeLiftoff,
}}
}
for _, u := range updates {
if u.Height < 0 {
// upgrade disabled
continue
@@ -109,7 +152,7 @@ func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, heig
var err error
f, ok := sm.stateMigrations[height]
if ok {
retCid, err = f(ctx, sm, cb, root, ts)
retCid, err = f(ctx, sm, cb, root, height, ts)
if err != nil {
return cid.Undef, err
}
@@ -118,6 +161,11 @@ func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, heig
return retCid, nil
}
func (sm *StateManager) hasExpensiveFork(ctx context.Context, height abi.ChainEpoch) bool {
_, ok := sm.expensiveUpgrades[height]
return ok
}
func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address, amt abi.TokenAmount) error {
fromAct, err := tree.GetActor(from)
if err != nil {
@@ -180,7 +228,7 @@ func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address,
return nil
}
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
// Some initial parameters
FundsForMiners := types.FromFil(1_000_000)
LookbackEpoch := abi.ChainEpoch(32000)
@@ -432,11 +480,9 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
return tree.Flush(ctx)
}
func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
store := sm.cs.Store(ctx)
epoch := ts.Height() - 1
if build.UpgradeLiftoffHeight <= epoch {
return cid.Undef, xerrors.Errorf("liftoff height must be beyond ignition height")
}
@@ -489,12 +535,42 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo
return tree.Flush(ctx)
}
func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
func UpgradeRefuel(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
store := sm.cs.Store(ctx)
tree, err := sm.StateTree(root)
if err != nil {
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
}
epoch := ts.Height() - 1
addr, err := address.NewFromString("t0122")
if err != nil {
return cid.Undef, xerrors.Errorf("getting address: %w", err)
}
info, err := store.Put(ctx, new(types.StateInfo))
err = resetMultisigVesting(ctx, store, tree, addr, 0, 0, big.Zero())
if err != nil {
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
}
err = resetMultisigVesting(ctx, store, tree, builtin.ReserveAddress, 0, 0, big.Zero())
if err != nil {
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
}
err = resetMultisigVesting(ctx, store, tree, builtin.RootVerifierAddress, 0, 0, big.Zero())
if err != nil {
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
}
return tree.Flush(ctx)
}
func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
buf := bufbstore.NewTieredBstore(sm.cs.Blockstore(), bstore.NewTemporarySync())
store := store.ActorStore(ctx, buf)
info, err := store.Put(ctx, new(types.StateInfo0))
if err != nil {
return cid.Undef, xerrors.Errorf("failed to create new state info for actors v2: %w", err)
}
@@ -518,8 +594,7 @@ func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, roo
}
newRoot, err := store.Put(ctx, &types.StateRoot{
// TODO: ActorUpgrade: should be state-tree specific, not just the actors version.
Version: actors.Version2,
Version: types.StateTreeVersion1,
Actors: newHamtRoot,
Info: info,
})
@@ -538,10 +613,19 @@ func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, roo
return cid.Undef, xerrors.Errorf("failed to load init actor after upgrade: %w", err)
}
{
from := buf
to := buf.Read()
if err := vm.Copy(ctx, from, to, newRoot); err != nil {
return cid.Undef, xerrors.Errorf("copying migrated tree: %w", err)
}
}
return newRoot, nil
}
func UpgradeLiftoff(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
func UpgradeLiftoff(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
tree, err := sm.StateTree(root)
if err != nil {
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
@@ -699,6 +783,7 @@ func makeKeyAddr(splitAddr address.Address, count uint64) (address.Address, erro
return addr, nil
}
// TODO: After the Liftoff epoch, refactor this to use resetMultisigVesting
func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store, tree *state.StateTree, startEpoch abi.ChainEpoch) error {
gb, err := sm.cs.GetGenesis()
if err != nil {
@@ -748,3 +833,34 @@ func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store,
return nil
}
func resetMultisigVesting(ctx context.Context, store adt0.Store, tree *state.StateTree, addr address.Address, startEpoch abi.ChainEpoch, duration abi.ChainEpoch, balance abi.TokenAmount) error {
act, err := tree.GetActor(addr)
if err != nil {
return xerrors.Errorf("getting actor: %w", err)
}
if !builtin.IsMultisigActor(act.Code) {
return xerrors.Errorf("actor wasn't msig: %w", err)
}
var msigState multisig0.State
if err := store.Get(ctx, act.Head, &msigState); err != nil {
return xerrors.Errorf("reading multisig state: %w", err)
}
msigState.StartEpoch = startEpoch
msigState.UnlockDuration = duration
msigState.InitialBalance = balance
act.Head, err = store.Put(ctx, &msigState)
if err != nil {
return xerrors.Errorf("writing new multisig state: %w", err)
}
if err := tree.SetActor(addr, act); err != nil {
return xerrors.Errorf("setting multisig actor: %w", err)
}
return nil
}
+86 -4
View File
@@ -10,8 +10,9 @@ import (
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/cbor"
"github.com/filecoin-project/specs-actors/actors/builtin"
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
"github.com/filecoin-project/specs-actors/actors/runtime"
"github.com/stretchr/testify/require"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/chain/actors"
@@ -76,7 +77,7 @@ func (ta testActor) Exports() []interface{} {
func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue {
rt.ValidateImmediateCallerAcceptAny()
rt.StateCreate(&testActorState{11})
fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
//fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
return abi.Empty
}
@@ -120,7 +121,7 @@ func TestForkHeightTriggers(t *testing.T) {
Network: 1,
Height: testForkHeight,
Migration: func(ctx context.Context, sm *StateManager, cb ExecCallback,
root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
cst := ipldcbor.NewCborStore(sm.ChainStore().Blockstore())
st, err := sm.StateTree(root)
@@ -173,7 +174,7 @@ func TestForkHeightTriggers(t *testing.T) {
var msgs []*types.SignedMessage
enc, err := actors.SerializeParams(&init_.ExecParams{CodeCID: (testActor{}).Code()})
enc, err := actors.SerializeParams(&init0.ExecParams{CodeCID: (testActor{}).Code()})
if err != nil {
t.Fatal(err)
}
@@ -233,3 +234,84 @@ func TestForkHeightTriggers(t *testing.T) {
}
}
}
func TestForkRefuseCall(t *testing.T) {
logging.SetAllLoggers(logging.LevelInfo)
ctx := context.TODO()
cg, err := gen.NewGenerator()
if err != nil {
t.Fatal(err)
}
sm, err := NewStateManagerWithUpgradeSchedule(
cg.ChainStore(), UpgradeSchedule{{
Network: 1,
Expensive: true,
Height: testForkHeight,
Migration: func(ctx context.Context, sm *StateManager, cb ExecCallback,
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
return root, nil
}}})
if err != nil {
t.Fatal(err)
}
inv := vm.NewActorRegistry()
inv.Register(nil, testActor{})
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
nvm, err := vm.NewVM(ctx, vmopt)
if err != nil {
return nil, err
}
nvm.SetInvoker(inv)
return nvm, nil
})
cg.SetStateManager(sm)
enc, err := actors.SerializeParams(&init0.ExecParams{CodeCID: (testActor{}).Code()})
if err != nil {
t.Fatal(err)
}
m := &types.Message{
From: cg.Banker(),
To: lotusinit.Address,
Method: builtin.MethodsInit.Exec,
Params: enc,
GasLimit: types.TestGasLimit,
Value: types.NewInt(0),
GasPremium: types.NewInt(0),
GasFeeCap: types.NewInt(0),
}
for i := 0; i < 50; i++ {
ts, err := cg.NextTipSet()
if err != nil {
t.Fatal(err)
}
ret, err := sm.CallWithGas(ctx, m, nil, ts.TipSet.TipSet())
switch ts.TipSet.TipSet().Height() {
case testForkHeight, testForkHeight + 1:
// If I had a fork, or I _will_ have a fork, it should fail.
require.Equal(t, ErrExpensiveFork, err)
default:
require.NoError(t, err)
require.True(t, ret.MsgRct.ExitCode.IsSuccess())
}
// Call just runs on the parent state for a tipset, so we only
// expect an error at the fork height.
ret, err = sm.Call(ctx, m, ts.TipSet.TipSet())
switch ts.TipSet.TipSet().Height() {
case testForkHeight + 1:
require.Equal(t, ErrExpensiveFork, err)
default:
require.NoError(t, err)
require.True(t, ret.MsgRct.ExitCode.IsSuccess())
}
}
}
+16 -7
View File
@@ -53,6 +53,10 @@ type StateManager struct {
// Maps chain epochs to upgrade functions.
stateMigrations map[abi.ChainEpoch]UpgradeFunc
// A set of potentially expensive/time consuming upgrades. Explicit
// calls for, e.g., gas estimation fail against this epoch with
// ErrExpensiveFork.
expensiveUpgrades map[abi.ChainEpoch]struct{}
stCache map[string][]cid.Cid
compWait map[string]chan struct{}
@@ -78,6 +82,7 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule
}
stateMigrations := make(map[abi.ChainEpoch]UpgradeFunc, len(us))
expensiveUpgrades := make(map[abi.ChainEpoch]struct{}, len(us))
var networkVersions []versionSpec
lastVersion := network.Version0
if len(us) > 0 {
@@ -87,6 +92,9 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule
if upgrade.Migration != nil {
stateMigrations[upgrade.Height] = upgrade.Migration
}
if upgrade.Expensive {
expensiveUpgrades[upgrade.Height] = struct{}{}
}
networkVersions = append(networkVersions, versionSpec{
networkVersion: lastVersion,
atOrBelow: upgrade.Height,
@@ -99,13 +107,14 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule
}
return &StateManager{
networkVersions: networkVersions,
latestVersion: lastVersion,
stateMigrations: stateMigrations,
newVM: vm.NewVM,
cs: cs,
stCache: make(map[string][]cid.Cid),
compWait: make(map[string]chan struct{}),
networkVersions: networkVersions,
latestVersion: lastVersion,
stateMigrations: stateMigrations,
expensiveUpgrades: expensiveUpgrades,
newVM: vm.NewVM,
cs: cs,
stCache: make(map[string][]cid.Cid),
compWait: make(map[string]chan struct{}),
}, nil
}
+1 -1
View File
@@ -387,7 +387,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
NtwkVersion: sm.GetNtwkVersion,
BaseFee: ts.Blocks()[0].ParentBaseFee,
}
vmi, err := vm.NewVM(ctx, vmopt)
vmi, err := sm.newVM(ctx, vmopt)
if err != nil {
return cid.Undef, nil, err
}
+8 -8
View File
@@ -1648,7 +1648,7 @@ func (t *StateRoot) MarshalCBOR(w io.Writer) error {
scratch := make([]byte, 9)
// t.Version (uint64) (uint64)
// t.Version (types.StateTreeVersion) (uint64)
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Version)); err != nil {
return err
@@ -1687,7 +1687,7 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Version (uint64) (uint64)
// t.Version (types.StateTreeVersion) (uint64)
{
@@ -1698,7 +1698,7 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.Version = uint64(extra)
t.Version = StateTreeVersion(extra)
}
// t.Actors (cid.Cid) (struct)
@@ -1728,22 +1728,22 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
return nil
}
var lengthBufStateInfo = []byte{128}
var lengthBufStateInfo0 = []byte{128}
func (t *StateInfo) MarshalCBOR(w io.Writer) error {
func (t *StateInfo0) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write(lengthBufStateInfo); err != nil {
if _, err := w.Write(lengthBufStateInfo0); err != nil {
return err
}
return nil
}
func (t *StateInfo) UnmarshalCBOR(r io.Reader) error {
*t = StateInfo{}
func (t *StateInfo0) UnmarshalCBOR(r io.Reader) error {
*t = StateInfo0{}
br := cbg.GetPeeker(r)
scratch := make([]byte, 8)
+14 -3
View File
@@ -2,9 +2,20 @@ package types
import "github.com/ipfs/go-cid"
// StateTreeVersion is the version of the state tree itself, independent of the
// network version or the actors version.
type StateTreeVersion uint64
const (
// StateTreeVersion0 corresponds to actors < v2.
StateTreeVersion0 StateTreeVersion = iota
// StateTreeVersion1 corresponds to actors >= v2.
StateTreeVersion1
)
type StateRoot struct {
// State root version. Versioned along with actors (for now).
Version uint64
// State tree version.
Version StateTreeVersion
// Actors tree. The structure depends on the state root version.
Actors cid.Cid
// Info. The structure depends on the state root version.
@@ -12,4 +23,4 @@ type StateRoot struct {
}
// TODO: version this.
type StateInfo struct{}
type StateInfo0 struct{}
+3 -3
View File
@@ -70,12 +70,12 @@ func (ar *ActorRegistry) Invoke(codeCid cid.Cid, rt vmr.Runtime, method abi.Meth
log.Errorf("no code for actor %s (Addr: %s)", codeCid, rt.Receiver())
return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "no code for actor %s(%d)(%s)", codeCid, method, hex.EncodeToString(params))
}
if err := act.predicate(rt, act.vmActor); err != nil {
return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "unsupported actor: %s", err)
}
if method >= abi.MethodNum(len(act.methods)) || act.methods[method] == nil {
return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "no method %d on actor", method)
}
if err := act.predicate(rt, act.vmActor); err != nil {
return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "unsupported actor: %s", err)
}
return act.methods[method](rt, params)
}
+5 -4
View File
@@ -49,6 +49,9 @@ func (m *Message) ValueReceived() abi.TokenAmount {
return m.msg.Value
}
// EnableGasTracing, if true, outputs gas tracing in execution traces.
var EnableGasTracing = false
type Runtime struct {
rt0.Message
rt0.Syscalls
@@ -477,7 +480,7 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
}
func (rt *Runtime) finilizeGasTracing() {
if enableTracing {
if EnableGasTracing {
if rt.lastGasCharge != nil {
rt.lastGasCharge.TimeTaken = time.Since(rt.lastGasChargeTime)
}
@@ -509,11 +512,9 @@ func (rt *Runtime) chargeGasFunc(skip int) func(GasCharge) {
}
var enableTracing = false
func (rt *Runtime) chargeGasInternal(gas GasCharge, skip int) aerrors.ActorError {
toUse := gas.Total()
if enableTracing {
if EnableGasTracing {
var callers [10]uintptr
cout := 0 //gruntime.Callers(2+skip, callers[:])
+20
View File
@@ -45,3 +45,23 @@ func TestRuntimePutErrors(t *testing.T) {
rt.StorePut(&NotAVeryGoodMarshaler{})
t.Error("expected panic")
}
func BenchmarkRuntime_CreateRuntimeChargeGas_TracingDisabled(b *testing.B) {
var (
cst = cbor.NewCborStore(nil)
gch = newGasCharge("foo", 1000, 1000)
)
b.ResetTimer()
EnableGasTracing = false
noop := func() bool { return EnableGasTracing }
for n := 0; n < b.N; n++ {
// flip the value and access it to make sure
// the compiler doesn't optimize away
EnableGasTracing = true
_ = noop()
EnableGasTracing = false
_ = (&Runtime{cst: cst}).chargeGasInternal(gch, 0)
}
}
+1 -1
View File
@@ -236,7 +236,7 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
}
rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac)
if enableTracing {
if EnableGasTracing {
rt.lastGasChargeTime = start
if parent != nil {
rt.lastGasChargeTime = parent.lastGasChargeTime
+95 -3
View File
@@ -7,6 +7,7 @@ import (
"fmt"
"html/template"
"io"
"io/ioutil"
"os"
"reflect"
"sort"
@@ -32,6 +33,7 @@ import (
"github.com/filecoin-project/go-state-types/exitcode"
"github.com/filecoin-project/lotus/api"
lapi "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/apibstore"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/state"
@@ -70,6 +72,7 @@ var stateCmd = &cli.Command{
stateMsgCostCmd,
stateMinerInfo,
stateMarketCmd,
stateExecTraceCmd,
},
}
@@ -313,6 +316,74 @@ var stateActiveSectorsCmd = &cli.Command{
},
}
var stateExecTraceCmd = &cli.Command{
Name: "exec-trace",
Usage: "Get the execution trace of a given message",
ArgsUsage: "<messageCid>",
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return ShowHelp(cctx, fmt.Errorf("must pass message cid"))
}
mcid, err := cid.Decode(cctx.Args().First())
if err != nil {
return fmt.Errorf("message cid was invalid: %s", err)
}
capi, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
msg, err := capi.ChainGetMessage(ctx, mcid)
if err != nil {
return err
}
lookup, err := capi.StateSearchMsg(ctx, mcid)
if err != nil {
return err
}
ts, err := capi.ChainGetTipSet(ctx, lookup.TipSet)
if err != nil {
return err
}
pts, err := capi.ChainGetTipSet(ctx, ts.Parents())
if err != nil {
return err
}
cso, err := capi.StateCompute(ctx, pts.Height(), nil, pts.Key())
if err != nil {
return err
}
var trace *api.InvocResult
for _, t := range cso.Trace {
if t.Msg.From == msg.From && t.Msg.Nonce == msg.Nonce {
trace = t
break
}
}
if trace == nil {
return fmt.Errorf("failed to find message in tipset trace output")
}
out, err := json.MarshalIndent(trace, "", " ")
if err != nil {
return err
}
fmt.Println(string(out))
return nil
},
}
var stateReplaySetCmd = &cli.Command{
Name: "replay",
Usage: "Replay a particular message within a tipset",
@@ -823,6 +894,10 @@ var stateComputeStateCmd = &cli.Command{
Name: "json",
Usage: "generate json output",
},
&cli.StringFlag{
Name: "compute-state-output",
Usage: "a json file containing pre-existing compute-state output, to generate html reports without rerunning state changes",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
@@ -862,9 +937,26 @@ var stateComputeStateCmd = &cli.Command{
}
}
stout, err := api.StateCompute(ctx, h, msgs, ts.Key())
if err != nil {
return err
var stout *lapi.ComputeStateOutput
if csofile := cctx.String("compute-state-output"); csofile != "" {
data, err := ioutil.ReadFile(csofile)
if err != nil {
return err
}
var o lapi.ComputeStateOutput
if err := json.Unmarshal(data, &o); err != nil {
return err
}
stout = &o
} else {
o, err := api.StateCompute(ctx, h, msgs, ts.Key())
if err != nil {
return err
}
stout = o
}
if cctx.Bool("json") {
+202 -82
View File
@@ -15,6 +15,7 @@ import (
"time"
"github.com/filecoin-project/lotus/chain/actors/builtin"
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
@@ -37,6 +38,7 @@ import (
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/tools/stats"
@@ -342,6 +344,18 @@ var runCmd = &cli.Command{
Usage: "process ProveCommitSector messages",
Value: true,
},
&cli.BoolFlag{
Name: "windowed-post",
EnvVars: []string{"LOTUS_PCR_WINDOWED_POST"},
Usage: "process SubmitWindowedPoSt messages and refund gas fees",
Value: false,
},
&cli.BoolFlag{
Name: "storage-deals",
EnvVars: []string{"LOTUS_PCR_STORAGE_DEALS"},
Usage: "process PublishStorageDeals messages and refund gas fees",
Value: false,
},
&cli.IntFlag{
Name: "head-delay",
EnvVars: []string{"LOTUS_PCR_HEAD_DELAY"},
@@ -378,6 +392,18 @@ var runCmd = &cli.Command{
Usage: "percent of refund to issue",
Value: 110,
},
&cli.StringFlag{
Name: "pre-fee-cap-max",
EnvVars: []string{"LOTUS_PCR_PRE_FEE_CAP_MAX"},
Usage: "messages with a fee cap larger than this will be skipped when processing pre commit messages",
Value: "0.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 {
go func() {
@@ -421,6 +447,8 @@ var runCmd = &cli.Command{
dryRun := cctx.Bool("dry-run")
preCommitEnabled := cctx.Bool("pre-commit")
proveCommitEnabled := cctx.Bool("prove-commit")
windowedPoStEnabled := cctx.Bool("windowed-post")
publishStorageDealsEnabled := cctx.Bool("storage-deals")
aggregateTipsets := cctx.Int("aggregate-tipsets")
minerRecoveryEnabled := cctx.Bool("miner-recovery")
minerRecoveryPeriod := abi.ChainEpoch(int64(cctx.Int("miner-recovery-period")))
@@ -428,6 +456,16 @@ var runCmd = &cli.Command{
minerRecoveryCutoff := uint64(cctx.Int("miner-recovery-cutoff"))
minerRecoveryBonus := uint64(cctx.Int("miner-recovery-bonus"))
preFeeCapMax, err := types.ParseFIL(cctx.String("pre-fee-cap-max"))
if err != nil {
return err
}
proveFeeCapMax, err := types.ParseFIL(cctx.String("prove-fee-cap-max"))
if err != nil {
return err
}
rf := &refunder{
api: api,
wallet: from,
@@ -438,6 +476,10 @@ var runCmd = &cli.Command{
dryRun: dryRun,
preCommitEnabled: preCommitEnabled,
proveCommitEnabled: proveCommitEnabled,
windowedPoStEnabled: windowedPoStEnabled,
publishStorageDealsEnabled: publishStorageDealsEnabled,
preFeeCapMax: types.BigInt(preFeeCapMax),
proveFeeCapMax: types.BigInt(proveFeeCapMax),
}
var refunds *MinersRefund = NewMinersRefund()
@@ -589,7 +631,12 @@ type refunder struct {
dryRun bool
preCommitEnabled bool
proveCommitEnabled bool
windowedPoStEnabled bool
publishStorageDealsEnabled bool
threshold big.Int
preFeeCapMax big.Int
proveFeeCapMax big.Int
}
func (r *refunder) FindMiners(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund, owner, worker, control bool) (*MinersRefund, error) {
@@ -817,6 +864,147 @@ func (r *refunder) EnsureMinerMinimums(ctx context.Context, tipset *types.TipSet
return refunds, nil
}
func (r *refunder) processTipsetStorageMarketActor(ctx context.Context, tipset *types.TipSet, msg api.Message, recp *types.MessageReceipt) (bool, string, types.BigInt, error) {
m := msg.Message
refundValue := types.NewInt(0)
var messageMethod string
switch m.Method {
case builtin0.MethodsMarket.PublishStorageDeals:
if !r.publishStorageDealsEnabled {
return false, messageMethod, types.NewInt(0), nil
}
messageMethod = "PublishStorageDeals"
if recp.ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
return false, messageMethod, types.NewInt(0), nil
}
refundValue = types.BigMul(types.NewInt(uint64(recp.GasUsed)), tipset.Blocks()[0].ParentBaseFee)
}
return true, messageMethod, refundValue, nil
}
func (r *refunder) processTipsetStorageMinerActor(ctx context.Context, tipset *types.TipSet, msg api.Message, recp *types.MessageReceipt) (bool, string, types.BigInt, error) {
m := msg.Message
refundValue := types.NewInt(0)
var messageMethod string
switch m.Method {
case builtin0.MethodsMiner.SubmitWindowedPoSt:
if !r.windowedPoStEnabled {
return false, messageMethod, types.NewInt(0), nil
}
messageMethod = "SubmitWindowedPoSt"
if recp.ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
return false, messageMethod, types.NewInt(0), nil
}
refundValue = types.BigMul(types.NewInt(uint64(recp.GasUsed)), tipset.Blocks()[0].ParentBaseFee)
case builtin0.MethodsMiner.ProveCommitSector:
if !r.proveCommitEnabled {
return false, messageMethod, types.NewInt(0), nil
}
messageMethod = "ProveCommitSector"
if recp.ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
return false, messageMethod, types.NewInt(0), nil
}
if m.GasFeeCap.GreaterThan(r.proveFeeCapMax) {
log.Debugw("skipping high fee cap message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "gas_fee_cap", m.GasFeeCap, "fee_cap_max", r.proveFeeCapMax)
return false, messageMethod, types.NewInt(0), nil
}
var sn abi.SectorNumber
var proveCommitSector miner0.ProveCommitSectorParams
if err := proveCommitSector.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
log.Warnw("failed to decode provecommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
return false, messageMethod, types.NewInt(0), nil
}
sn = proveCommitSector.SectorNumber
// We use the parent tipset key because precommit information is removed when ProveCommitSector is executed
precommitChainInfo, err := r.api.StateSectorPreCommitInfo(ctx, m.To, sn, tipset.Parents())
if err != nil {
log.Warnw("failed to get precommit info for sector", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
return false, messageMethod, types.NewInt(0), nil
}
precommitTipset, err := r.api.ChainGetTipSetByHeight(ctx, precommitChainInfo.PreCommitEpoch, tipset.Key())
if err != nil {
log.Warnf("failed to lookup precommit epoch", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
return false, messageMethod, types.NewInt(0), nil
}
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitChainInfo.Info, precommitTipset.Key())
if err != nil {
log.Warnw("failed to get initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
return false, messageMethod, types.NewInt(0), nil
}
collateral = big.Sub(collateral, precommitChainInfo.PreCommitDeposit)
if collateral.LessThan(big.Zero()) {
log.Debugw("skipping zero pledge collateral difference", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
return false, messageMethod, types.NewInt(0), nil
}
refundValue = collateral
if r.refundPercent > 0 {
refundValue = types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.refundPercent)))
}
case builtin0.MethodsMiner.PreCommitSector:
if !r.preCommitEnabled {
return false, messageMethod, types.NewInt(0), nil
}
messageMethod = "PreCommitSector"
if recp.ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
return false, messageMethod, types.NewInt(0), nil
}
if m.GasFeeCap.GreaterThan(r.preFeeCapMax) {
log.Debugw("skipping high fee cap message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "gas_fee_cap", m.GasFeeCap, "fee_cap_max", r.preFeeCapMax)
return false, messageMethod, types.NewInt(0), nil
}
var precommitInfo miner.SectorPreCommitInfo
if err := precommitInfo.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
log.Warnw("failed to decode precommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
return false, messageMethod, types.NewInt(0), nil
}
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitInfo, tipset.Key())
if err != nil {
log.Warnw("failed to calculate initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", precommitInfo.SectorNumber)
return false, messageMethod, types.NewInt(0), nil
}
refundValue = collateral
if r.refundPercent > 0 {
refundValue = types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.refundPercent)))
}
default:
return false, messageMethod, types.NewInt(0), nil
}
return true, messageMethod, refundValue, nil
}
func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund) (*MinersRefund, error) {
cids := tipset.Cids()
if len(cids) == 0 {
@@ -841,9 +1029,9 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu
return nil, nil
}
refundValue := types.NewInt(0)
tipsetRefunds := NewMinersRefund()
for i, msg := range msgs {
refundValue := types.NewInt(0)
m := msg.Message
a, err := r.api.StateGetActor(ctx, m.To, tipset.Key())
@@ -852,91 +1040,23 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu
continue
}
if !builtin.IsStorageMinerActor(a.Code) {
continue
}
var messageMethod string
var processed bool
switch m.Method {
case builtin0.MethodsMiner.ProveCommitSector:
if !r.proveCommitEnabled {
continue
}
messageMethod = "ProveCommitSector"
if recps[i].ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recps[i].ExitCode)
continue
}
var sn abi.SectorNumber
var proveCommitSector miner0.ProveCommitSectorParams
if err := proveCommitSector.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
log.Warnw("failed to decode provecommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
continue
}
sn = proveCommitSector.SectorNumber
// We use the parent tipset key because precommit information is removed when ProveCommitSector is executed
precommitChainInfo, err := r.api.StateSectorPreCommitInfo(ctx, m.To, sn, tipset.Parents())
if err != nil {
log.Warnw("failed to get precommit info for sector", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
continue
}
precommitTipset, err := r.api.ChainGetTipSetByHeight(ctx, precommitChainInfo.PreCommitEpoch, tipset.Key())
if err != nil {
log.Warnf("failed to lookup precommit epoch", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
continue
}
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitChainInfo.Info, precommitTipset.Key())
if err != nil {
log.Warnw("failed to get initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
}
collateral = big.Sub(collateral, precommitChainInfo.PreCommitDeposit)
if collateral.LessThan(big.Zero()) {
log.Debugw("skipping zero pledge collateral difference", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
continue
}
refundValue = collateral
case builtin0.MethodsMiner.PreCommitSector:
if !r.preCommitEnabled {
continue
}
messageMethod = "PreCommitSector"
if recps[i].ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recps[i].ExitCode)
continue
}
var precommitInfo miner.SectorPreCommitInfo
if err := precommitInfo.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
log.Warnw("failed to decode precommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
continue
}
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitInfo, tipset.Key())
if err != nil {
log.Warnw("failed to calculate initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", precommitInfo.SectorNumber)
continue
}
refundValue = collateral
default:
continue
if m.To == market.Address {
processed, messageMethod, refundValue, err = r.processTipsetStorageMarketActor(ctx, tipset, msg, recps[i])
}
if r.refundPercent > 0 {
refundValue = types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.refundPercent)))
if builtin.IsStorageMinerActor(a.Code) {
processed, messageMethod, refundValue, err = r.processTipsetStorageMinerActor(ctx, tipset, msg, recps[i])
}
if err != nil {
log.Errorw("error while processing message", "cid", msg.Cid)
continue
}
if !processed {
continue
}
log.Debugw(
+28 -5
View File
@@ -5,6 +5,8 @@ import (
"math"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/lotus/chain/types"
@@ -32,6 +34,10 @@ var noncefix = &cli.Command{
&cli.BoolFlag{
Name: "auto",
},
&cli.Int64Flag{
Name: "gas-fee-cap",
Usage: "specify gas fee cap for nonce filling messages",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := lcli.GetFullNodeAPI(cctx)
@@ -84,15 +90,32 @@ var noncefix = &cli.Command{
}
fmt.Printf("Creating %d filler messages (%d ~ %d)\n", end-start, start, end)
ts, err := api.ChainHead(ctx)
if err != nil {
return err
}
feeCap := big.Mul(ts.Blocks()[0].ParentBaseFee, big.NewInt(2)) // default fee cap to 2 * parent base fee
if fcf := cctx.Int64("gas-fee-cap"); fcf != 0 {
feeCap = abi.NewTokenAmount(fcf)
}
for i := start; i < end; i++ {
msg := &types.Message{
From: addr,
To: addr,
Value: types.NewInt(1),
Nonce: i,
From: addr,
To: addr,
Value: types.NewInt(0),
Nonce: i,
GasLimit: 1000000,
GasFeeCap: feeCap,
GasPremium: abi.NewTokenAmount(5),
}
smsg, err := api.WalletSignMessage(ctx, addr, msg)
if err != nil {
return err
}
_, err = api.MpoolPushMessage(ctx, msg, nil)
_, err = api.MpoolPush(ctx, smsg)
if err != nil {
return err
}
+8 -8
View File
@@ -33,7 +33,7 @@ var runCmd = &cli.Command{
Usage: "Start a lotus miner process",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "api",
Name: "miner-api",
Usage: "2345",
},
&cli.BoolFlag{
@@ -61,7 +61,7 @@ var runCmd = &cli.Command{
nodeApi, ncloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
return xerrors.Errorf("getting full node api: %w", err)
}
defer ncloser()
ctx := lcli.DaemonContext(cctx)
@@ -112,29 +112,29 @@ var runCmd = &cli.Command{
node.Online(),
node.Repo(r),
node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("api") },
node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("miner-api") },
node.Override(new(dtypes.APIEndpoint), func() (dtypes.APIEndpoint, error) {
return multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/" + cctx.String("api"))
return multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/" + cctx.String("miner-api"))
})),
node.Override(new(api.FullNode), nodeApi),
)
if err != nil {
return err
return xerrors.Errorf("creating node: %w", err)
}
endpoint, err := r.APIEndpoint()
if err != nil {
return err
return xerrors.Errorf("getting API endpoint: %w", err)
}
// Bootstrap with full node
remoteAddrs, err := nodeApi.NetAddrsListen(ctx)
if err != nil {
return err
return xerrors.Errorf("getting full node libp2p address: %w", err)
}
if err := minerapi.NetConnect(ctx, remoteAddrs); err != nil {
return err
return xerrors.Errorf("connecting to full node (libp2p): %w", err)
}
log.Infof("Remote version %s", v)
+23
View File
@@ -31,6 +31,10 @@ const metaFile = "sectorstore.json"
var storageCmd = &cli.Command{
Name: "storage",
Usage: "manage sector storage",
Description: `Sectors can be stored across many filesystem paths. These
commands provide ways to manage the storage the miner will used to store sectors
long term for proving (references as 'store') as well as how sectors will be
stored while moving through the sealing pipeline (references as 'seal').`,
Subcommands: []*cli.Command{
storageAttachCmd,
storageListCmd,
@@ -41,6 +45,25 @@ var storageCmd = &cli.Command{
var storageAttachCmd = &cli.Command{
Name: "attach",
Usage: "attach local storage path",
Description: `Storage can be attached to the miner using this command. The storage volume
list is stored local to the miner in $LOTUS_MINER_PATH/storage.json. We do not
recommend manually modifying this value without further understanding of the
storage system.
Each storage volume contains a configuration file which describes the
capabilities of the volume. When the '--init' flag is provided, this file will
be created using the additional flags.
Weight
A high weight value means data will be more likely to be stored in this path
Seal
Data for the sealing process will be stored here
Store
Finalized sectors that will be moved here for long term storage and be proven
over time
`,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "init",
+6 -6
View File
@@ -198,8 +198,8 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
Preroot: root,
Epoch: execTs.Height(),
Message: m,
CircSupply: &circSupplyDetail.FilCirculating,
BaseFee: &basefee,
CircSupply: circSupplyDetail.FilCirculating,
BaseFee: basefee,
})
if err != nil {
return fmt.Errorf("failed to execute precursor message: %w", err)
@@ -229,8 +229,8 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
Preroot: preroot,
Epoch: execTs.Height(),
Message: msg,
CircSupply: &circSupplyDetail.FilCirculating,
BaseFee: &basefee,
CircSupply: circSupplyDetail.FilCirculating,
BaseFee: basefee,
})
if err != nil {
return fmt.Errorf("failed to execute message: %w", err)
@@ -260,8 +260,8 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
Preroot: preroot,
Epoch: execTs.Height(),
Message: msg,
CircSupply: &circSupplyDetail.FilCirculating,
BaseFee: &basefee,
CircSupply: circSupplyDetail.FilCirculating,
BaseFee: basefee,
})
if err != nil {
return fmt.Errorf("failed to execute message: %w", err)
+33 -14
View File
@@ -2,6 +2,7 @@ package conformance
import (
"context"
gobig "math/big"
"os"
"github.com/filecoin-project/lotus/chain/state"
@@ -14,6 +15,7 @@ import (
"github.com/filecoin-project/lotus/lib/blockstore"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/test-vectors/schema"
@@ -80,7 +82,7 @@ type ExecuteTipsetResult struct {
func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, preroot cid.Cid, parentEpoch abi.ChainEpoch, tipset *schema.Tipset) (*ExecuteTipsetResult, error) {
var (
syscalls = mkFakedSigSyscalls(vm.Syscalls(ffiwrapper.ProofVerifier))
vmRand = new(testRand)
vmRand = NewFixedRand()
cs = store.NewChainStore(bs, ds, syscalls)
sm = stmgr.NewStateManager(cs)
@@ -143,8 +145,12 @@ type ExecuteMessageParams struct {
Preroot cid.Cid
Epoch abi.ChainEpoch
Message *types.Message
CircSupply *abi.TokenAmount
BaseFee *abi.TokenAmount
CircSupply abi.TokenAmount
BaseFee abi.TokenAmount
// Rand is an optional vm.Rand implementation to use. If nil, the driver
// will use a vm.Rand that returns a fixed value for all calls.
Rand vm.Rand
}
// ExecuteMessage executes a conformance test vector message in a temporary VM.
@@ -155,14 +161,8 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
_ = os.Setenv("LOTUS_DISABLE_VM_BUF", "iknowitsabadidea")
}
basefee := DefaultBaseFee
if params.BaseFee != nil {
basefee = *params.BaseFee
}
circSupply := DefaultCirculatingSupply
if params.CircSupply != nil {
circSupply = *params.CircSupply
if params.Rand == nil {
params.Rand = NewFixedRand()
}
// dummy state manager; only to reference the GetNetworkVersion method,
@@ -172,13 +172,13 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
vmOpts := &vm.VMOpts{
StateBase: params.Preroot,
Epoch: params.Epoch,
Rand: &testRand{}, // TODO always succeeds; need more flexibility.
Bstore: bs,
Syscalls: mkFakedSigSyscalls(vm.Syscalls(ffiwrapper.ProofVerifier)), // TODO always succeeds; need more flexibility.
CircSupplyCalc: func(_ context.Context, _ abi.ChainEpoch, _ *state.StateTree) (abi.TokenAmount, error) {
return circSupply, nil
return params.CircSupply, nil
},
BaseFee: basefee,
Rand: params.Rand,
BaseFee: params.BaseFee,
NtwkVersion: sm.GetNtwkVersion,
}
@@ -231,3 +231,22 @@ func toChainMsg(msg *types.Message) (ret types.ChainMsg) {
}
return ret
}
// BaseFeeOrDefault converts a basefee as passed in a test vector (go *big.Int
// type) to an abi.TokenAmount, or if nil it returns the DefaultBaseFee.
func BaseFeeOrDefault(basefee *gobig.Int) abi.TokenAmount {
if basefee == nil {
return DefaultBaseFee
}
return big.NewFromGo(basefee)
}
// CircSupplyOrDefault converts a circulating supply as passed in a test vector
// (go *big.Int type) to an abi.TokenAmount, or if nil it returns the
// DefaultCirculatingSupply.
func CircSupplyOrDefault(circSupply *gobig.Int) abi.TokenAmount {
if circSupply == nil {
return DefaultBaseFee
}
return big.NewFromGo(circSupply)
}
+28
View File
@@ -0,0 +1,28 @@
package conformance
import (
"context"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/chain/vm"
)
type fixedRand struct{}
var _ vm.Rand = (*fixedRand)(nil)
// NewFixedRand creates a test vm.Rand that always returns fixed bytes value
// of utf-8 string 'i_am_random_____i_am_random_____'.
func NewFixedRand() vm.Rand {
return &fixedRand{}
}
func (r *fixedRand) GetChainRandomness(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) {
return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes.
}
func (r *fixedRand) GetBeaconRandomness(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) {
return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes.
}
+4 -16
View File
@@ -13,9 +13,7 @@ import (
"github.com/fatih/color"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/exitcode"
"github.com/filecoin-project/test-vectors/schema"
"github.com/ipfs/go-blockservice"
"github.com/ipfs/go-cid"
ds "github.com/ipfs/go-datastore"
@@ -24,6 +22,8 @@ import (
"github.com/ipfs/go-merkledag"
"github.com/ipld/go-car"
"github.com/filecoin-project/test-vectors/schema"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/lib/blockstore"
@@ -46,18 +46,6 @@ func ExecuteMessageVector(r Reporter, vector *schema.TestVector) {
// Create a new Driver.
driver := NewDriver(ctx, vector.Selector, DriverOpts{DisableVMFlush: true})
var circSupply *abi.TokenAmount
if cs := vector.Pre.CircSupply; cs != nil {
ta := big.NewFromGo(cs)
circSupply = &ta
}
var basefee *abi.TokenAmount
if bf := vector.Pre.BaseFee; bf != nil {
ta := big.NewFromGo(bf)
basefee = &ta
}
// Apply every message.
for i, m := range vector.ApplyMessages {
msg, err := types.DecodeMessage(m.Bytes)
@@ -76,8 +64,8 @@ func ExecuteMessageVector(r Reporter, vector *schema.TestVector) {
Preroot: root,
Epoch: abi.ChainEpoch(epoch),
Message: msg,
CircSupply: circSupply,
BaseFee: basefee,
BaseFee: BaseFeeOrDefault(vector.Pre.BaseFee),
CircSupply: CircSupplyOrDefault(vector.Pre.CircSupply),
})
if err != nil {
r.Fatalf("fatal failure when executing message: %s", err)
+1 -13
View File
@@ -6,28 +6,16 @@ import (
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/specs-actors/actors/runtime"
cbor "github.com/ipfs/go-ipld-cbor"
)
type testRand struct{}
var _ vm.Rand = (*testRand)(nil)
func (r *testRand) GetChainRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes.
}
func (r *testRand) GetBeaconRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes.
}
type testSyscalls struct {
runtime.Syscalls
}
+7 -2
View File
@@ -30,10 +30,15 @@ type StoragePath struct {
// LocalStorageMeta [path]/sectorstore.json
type LocalStorageMeta struct {
ID ID
ID ID
// A high weight means data is more likely to be stored in this path
Weight uint64 // 0 = readonly
CanSeal bool
// Intermediate data for the sealing process will be stored here
CanSeal bool
// Finalized sectors that will be proved over time will be stored here
CanStore bool
}
+1 -1
View File
@@ -27,7 +27,7 @@ func main() {
types.ExpTipSet{},
types.BeaconEntry{},
types.StateRoot{},
types.StateInfo{},
types.StateInfo0{},
)
if err != nil {
fmt.Println(err)
+2 -1
View File
@@ -176,7 +176,8 @@
"CompactPartitions",
"CompactSectorNumbers",
"ConfirmUpdateWorkerKey",
"RepayDebt"
"RepayDebt",
"ChangeOwnerAddress"
],
"fil/2/storagepower": [
"Send",
+7 -5
View File
@@ -11,16 +11,16 @@ import (
"sync/atomic"
"time"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/types"
"github.com/google/uuid"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/gen"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
"github.com/filecoin-project/lotus/genesis"
)
@@ -69,6 +69,8 @@ func (api *api) Spawn() (nodeInfo, error) {
Meta: (&genesis.AccountMeta{Owner: genm.Owner}).ActorMeta(),
})
template.VerifregRootKey = gen.DefaultVerifregRootkeyActor
template.RemainderAccount = gen.DefaultRemainderAccountActor
template.NetworkName = "pond-" + uuid.New().String()
tb, err := json.Marshal(&template)
if err != nil {
@@ -188,7 +190,7 @@ func (api *api) SpawnStorage(fullNodeRepo string) (nodeInfo, error) {
mux := newWsMux()
cmd = exec.Command("./lotus-miner", "run", "--api", fmt.Sprintf("%d", 2500+id), "--nosync")
cmd = exec.Command("./lotus-miner", "run", "--miner-api", fmt.Sprintf("%d", 2500+id), "--nosync")
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile, mux.errpw)
cmd.Stdout = io.MultiWriter(os.Stdout, logfile, mux.outpw)
cmd.Env = append(os.Environ(), "LOTUS_MINER_PATH="+dir, "LOTUS_PATH="+fullNodeRepo)
@@ -248,7 +250,7 @@ func (api *api) RestartNode(id int32) (nodeInfo, error) {
var cmd *exec.Cmd
if nd.meta.Storage {
cmd = exec.Command("./lotus-miner", "run", "--api", fmt.Sprintf("%d", 2500+id), "--nosync")
cmd = exec.Command("./lotus-miner", "run", "--miner-api", fmt.Sprintf("%d", 2500+id), "--nosync")
} else {
cmd = exec.Command("./lotus", "daemon", "--api", fmt.Sprintf("%d", 2500+id))
}
+22 -2
View File
@@ -254,11 +254,31 @@ func (a *ChainAPI) ChainStatObj(ctx context.Context, obj cid.Cid, base cid.Cid)
}
func (a *ChainAPI) ChainSetHead(ctx context.Context, tsk types.TipSetKey) error {
ts, err := a.Chain.GetTipSetFromKey(tsk)
newHeadTs, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return a.Chain.SetHead(ts)
currentTs, err := a.ChainHead(ctx)
if err != nil {
return xerrors.Errorf("getting head: %w", err)
}
for currentTs.Height() >= newHeadTs.Height() {
for _, blk := range currentTs.Key().Cids() {
err = a.Chain.UnmarkBlockAsValidated(ctx, blk)
if err != nil {
return xerrors.Errorf("unmarking block as validated %s: %w", blk, err)
}
}
currentTs, err = a.ChainGetTipSet(ctx, currentTs.Parents())
if err != nil {
return xerrors.Errorf("loading tipset: %w", err)
}
}
return a.Chain.SetHead(newHeadTs)
}
func (a *ChainAPI) ChainGetGenesis(ctx context.Context) (*types.TipSet, error) {
+12 -1
View File
@@ -160,7 +160,18 @@ func (a *GasAPI) GasEstimateGasLimit(ctx context.Context, msgIn *types.Message,
priorMsgs = append(priorMsgs, m)
}
res, err := a.Stmgr.CallWithGas(ctx, &msg, priorMsgs, ts)
// Try calling until we find a height with no migration.
var res *api.InvocResult
for {
res, err = a.Stmgr.CallWithGas(ctx, &msg, priorMsgs, ts)
if err != stmgr.ErrExpensiveFork {
break
}
ts, err = a.Chain.GetTipSetFromKey(ts.Parents())
if err != nil {
return -1, xerrors.Errorf("getting parent tipset: %w", err)
}
}
if err != nil {
return -1, xerrors.Errorf("CallWithGas failed: %w", err)
}
+12 -2
View File
@@ -307,12 +307,22 @@ func (a *StateAPI) StateMinerPower(ctx context.Context, addr address.Address, ts
}, nil
}
func (a *StateAPI) StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (*api.InvocResult, error) {
func (a *StateAPI) StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (res *api.InvocResult, err error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return a.StateManager.Call(ctx, msg, ts)
for {
res, err = a.StateManager.Call(ctx, msg, ts)
if err != stmgr.ErrExpensiveFork {
break
}
ts, err = a.Chain.GetTipSetFromKey(ts.Parents())
if err != nil {
return nil, xerrors.Errorf("getting parent tipset: %w", err)
}
}
return res, err
}
func (a *StateAPI) StateReplay(ctx context.Context, tsk types.TipSetKey, mc cid.Cid) (*api.InvocResult, error) {