diff --git a/CHANGELOG.md b/CHANGELOG.md index a420421de89..e4fc4c67bec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,106 @@ # Lotus changelog +# 1.14.2 / 2022-02-24 + +This is an **optional** release of lotus, that's had a couple more improvements w.r.t Snap experience for storage providers in preparation of the[upcoming OhSnap upgrade](https://github.com/filecoin-project/community/discussions/74?sort=new#discussioncomment-1922550). + +Note that the network is STILL scheduled to upgrade to v15 on March 1st at 2022-03-01T15:00:00Z. All node operators, including storage providers, must upgrade to at least Lotus v1.14.0 before that time. Storage providers must update their daemons, miners, and worker(s). + +Wanna know how to Snap your deal? Check [this](https://github.com/filecoin-project/lotus/discussions/8141) out! + +## Bug Fixes +- fix lotus-bench for sealing jobs (#8173) +- fix:sealing:really-do-it flag for abort upgrade (#8181) +- fix:proving:post check sector handles snap deals replica faults (#8177) +- fix: sealing: missing file type (#8180) + +## Others +- Retract force-pushed v1.14.0 to work around stale gomod caches (#8159): We originally tagged v1.14.0 off the wrong + commit and fixed that by a force push, in which is a really bad practise since it messes up the go mod. Therefore, + we want to retract it and users may use v1.14.1&^. + +## Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| @zenground0 | 2 | +73/-58 | 12 | +| @eben.xie | 1 | +7/-0 | 1 | +| @jennijuju | 1 | +4/-0 | 1 | +| @jennijuju | 1 | +2/-1 | 1 | +| @ribasushi | 1 | +2/-0 | 1 | + +# 1.14.1 / 2022-02-18 + +This is an **optional** release of lotus, that fixes the incorrect *comment* of network v15 OhSnap upgrade **date**. Note the actual upgrade epoch in [v1.14.0](https://github.com/filecoin-project/lotus/releases/tag/v1.14.0) was correct. + +# 1.14.0 / 2022-02-17 + +This is a MANDATORY release of Lotus that introduces [Filecoin network v15, +codenamed the OhSnap upgrade](https://github.com/filecoin-project/community/discussions/74?sort=new#discussioncomment-1922550). + +The network is scheduled to upgrade to v15 on March 1st at 2022-03-01T15:00:00Z. All node operators, including storage providers, must upgrade to this release (or a later release) before that time. Storage providers must update their daemons, miners, and worker(s). + +The OhSnap upgrade introduces the following FIPs, delivered in [actors v7](https://github.com/filecoin-project/specs-actors/releases/tag/v7.0.0): +- [FIP-0019 Snap Deals](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0019.md) +- [FIP-0028 Remove Datacap from Verified clients](https://github.com/filecoin-project/FIPs/pull/226) + +It is recommended that storage providers download the new params before updating their node, miner, and workers. To do so: + +- Download Lotus v1.14.0 or later +- run `make lotus-shed` +- run `./lotus-shed fetch-params` with the appropriate `proving-params` flag +- Upgrade the Lotus daemon and miner **when the previous step is complete** + +All node operators, including storage providers, should be aware that a pre-migration will begin at 2022-03-01T13:30:00Z (90 minutes before the real upgrade). The pre-migration will take between 20 and 50 minutes, depending on hardware specs. During this time, expect slower block validation times, increased CPU and memory usage, and longer delays for API queries. + +## New Features and Changes +- Integrate actor v7-rc1: + - Integrate v7 actors ([#7617](https://github.com/filecoin-project/lotus/pull/7617)) + - feat: state: Fast migration for v15 ([#7933](https://github.com/filecoin-project/lotus/pull/7933)) + - fix: blockstore: Add missing locks to autobatch::Get() [#7939](https://github.com/filecoin-project/lotus/pull/7939)) + - correctness fixes for the autobatch blockstore ([#7940](https://github.com/filecoin-project/lotus/pull/7940)) +- Implement and support [FIP-0019 Snap Deals](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0019.md) + - chore: deps: Integrate proof v11.0.0 ([#7923](https://github.com/filecoin-project/lotus/pull/7923)) + - Snap Deals Lotus Integration: FSM Posting and integration test ([#7810](https://github.com/filecoin-project/lotus/pull/7810)) + - Feat/sector storage unseal ([#7730](https://github.com/filecoin-project/lotus/pull/7730)) + - Feat/snap deals storage ([#7615](https://github.com/filecoin-project/lotus/pull/7615)) + - fix: sealing: Add more deal expiration checks during PRU pipeline ([#7871](https://github.com/filecoin-project/lotus/pull/7871)) + - chore: deps: Update go-paramfetch ([#7917](https://github.com/filecoin-project/lotus/pull/7917)) + - feat: #7880 gas: add gas charge for VerifyReplicaUpdate ([#7897](https://github.com/filecoin-project/lotus/pull/7897)) + - enhancement: sectors: disable existing cc upgrade path 2 days before the upgrade epoch ([#7900](https://github.com/filecoin-project/lotus/pull/7900)) + +## Improvements +- updating to new datastore/blockstore code with contexts ([#7646](https://github.com/filecoin-project/lotus/pull/7646)) +- reorder transfer checks so as to ensure sending 2B FIL to yourself fails if you don't have that amount ([#7637](https://github.com/filecoin-project/lotus/pull/7637)) +- VM: Circ supply should be constant per epoch ([#7811](https://github.com/filecoin-project/lotus/pull/7811)) + +## Bug Fixes +- Fix: state: circsuypply calc around null blocks ([#7890](https://github.com/filecoin-project/lotus/pull/7890)) +- Mempool msg selection should respect block message limits ([#7321](https://github.com/filecoin-project/lotus/pull/7321)) + SplitStore: supress compaction near upgrades ([#7734](https://github.com/filecoin-project/lotus/pull/7734)) + +## Others +- chore: create pull_request_template.md ([#7726](https://github.com/filecoin-project/lotus/pull/7726)) + +## Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Aayush Rajasekaran | 41 | +5538/-1205 | 189 | +| zenground0 | 11 | +3316/-524 | 124 | +| Jennifer Wang | 29 | +714/-599 | 68 | +| ZenGround0 | 3 | +263/-25 | 11 | +| c r | 2 | +198/-30 | 6 | +| vyzo | 4 | +189/-7 | 7 | +| Aayush | 11 | +146/-48 | 49 | +| web3-bot | 10 | +99/-17 | 10 | +| Steven Allen | 1 | +55/-37 | 1 | +| Jiaying Wang | 5 | +30/-8 | 5 | +| Jakub Sztandera | 2 | +8/-3 | 3 | +| Łukasz Magiera | 1 | +3/-3 | 2 | +| Travis Person | 1 | +2/-2 | 2 | +| Rod Vagg | 1 | +2/-2 | 2 | + # v1.13.2 / 2022-01-09 Lotus v1.13.2 is a *highly recommended* feature release with remarkable retrieval improvements, new features like diff --git a/api/api_gateway.go b/api/api_gateway.go index fbe2e0cd66e..be4b3b83cb4 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -45,8 +45,9 @@ type Gateway interface { GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) - MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) MsigGetPending(context.Context, address.Address, types.TipSetKey) ([]*MsigTransaction, error) + MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) + MsigGetVestingSchedule(ctx context.Context, addr address.Address, tsk types.TipSetKey) (MsigVesting, error) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (DealCollateralBounds, error) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) diff --git a/api/api_storage.go b/api/api_storage.go index a66f22d0484..da66a9a0358 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -256,7 +256,7 @@ type StorageMiner interface { // the path specified when calling CreateBackup is within the base path CreateBackup(ctx context.Context, fpath string) error //perm:admin - CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storage.SectorRef, expensive bool) (map[abi.SectorNumber]string, error) //perm:admin + CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storage.SectorRef, update []bool, expensive bool) (map[abi.SectorNumber]string, error) //perm:admin ComputeProof(ctx context.Context, ssi []builtin.ExtendedSectorInfo, rand abi.PoStRandomness, poStEpoch abi.ChainEpoch, nv abinetwork.Version) ([]builtin.PoStProof, error) //perm:read } diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 15866e3e50b..cd3e1ad3533 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -516,6 +516,8 @@ type GatewayStruct struct { MsigGetVested func(p0 context.Context, p1 address.Address, p2 types.TipSetKey, p3 types.TipSetKey) (types.BigInt, error) `` + MsigGetVestingSchedule func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MsigVesting, error) `` + StateAccountKey func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `` StateDealProviderCollateralBounds func(p0 context.Context, p1 abi.PaddedPieceSize, p2 bool, p3 types.TipSetKey) (DealCollateralBounds, error) `` @@ -625,7 +627,7 @@ type StorageMinerStruct struct { ActorSectorSize func(p0 context.Context, p1 address.Address) (abi.SectorSize, error) `perm:"read"` - CheckProvable func(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 bool) (map[abi.SectorNumber]string, error) `perm:"admin"` + CheckProvable func(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 []bool, p4 bool) (map[abi.SectorNumber]string, error) `perm:"admin"` ComputeProof func(p0 context.Context, p1 []builtin.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtin.PoStProof, error) `perm:"read"` @@ -3285,6 +3287,17 @@ func (s *GatewayStub) MsigGetVested(p0 context.Context, p1 address.Address, p2 t return *new(types.BigInt), ErrNotSupported } +func (s *GatewayStruct) MsigGetVestingSchedule(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MsigVesting, error) { + if s.Internal.MsigGetVestingSchedule == nil { + return *new(MsigVesting), ErrNotSupported + } + return s.Internal.MsigGetVestingSchedule(p0, p1, p2) +} + +func (s *GatewayStub) MsigGetVestingSchedule(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MsigVesting, error) { + return *new(MsigVesting), ErrNotSupported +} + func (s *GatewayStruct) StateAccountKey(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) { if s.Internal.StateAccountKey == nil { return *new(address.Address), ErrNotSupported @@ -3747,14 +3760,14 @@ func (s *StorageMinerStub) ActorSectorSize(p0 context.Context, p1 address.Addres return *new(abi.SectorSize), ErrNotSupported } -func (s *StorageMinerStruct) CheckProvable(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 bool) (map[abi.SectorNumber]string, error) { +func (s *StorageMinerStruct) CheckProvable(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 []bool, p4 bool) (map[abi.SectorNumber]string, error) { if s.Internal.CheckProvable == nil { return *new(map[abi.SectorNumber]string), ErrNotSupported } - return s.Internal.CheckProvable(p0, p1, p2, p3) + return s.Internal.CheckProvable(p0, p1, p2, p3, p4) } -func (s *StorageMinerStub) CheckProvable(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 bool) (map[abi.SectorNumber]string, error) { +func (s *StorageMinerStub) CheckProvable(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 []bool, p4 bool) (map[abi.SectorNumber]string, error) { return *new(map[abi.SectorNumber]string), ErrNotSupported } diff --git a/api/version.go b/api/version.go index 228dcbd10d3..9f4f7351361 100644 --- a/api/version.go +++ b/api/version.go @@ -57,7 +57,7 @@ var ( FullAPIVersion0 = newVer(1, 5, 0) FullAPIVersion1 = newVer(2, 2, 0) - MinerAPIVersion0 = newVer(1, 3, 0) + MinerAPIVersion0 = newVer(1, 4, 0) WorkerAPIVersion0 = newVer(1, 5, 0) ) diff --git a/blockstore/splitstore/splitstore_reify.go b/blockstore/splitstore/splitstore_reify.go index 6529007471d..85c4fa2894e 100644 --- a/blockstore/splitstore/splitstore_reify.go +++ b/blockstore/splitstore/splitstore_reify.go @@ -1,6 +1,7 @@ package splitstore import ( + "errors" "runtime" "sync/atomic" @@ -10,13 +11,12 @@ import ( cid "github.com/ipfs/go-cid" ) -var EnableReification = false +var ( + errReifyLimit = errors.New("reification limit reached") + ReifyLimit = 16384 +) func (s *SplitStore) reifyColdObject(c cid.Cid) { - if !EnableReification { - return - } - if !s.isWarm() { return } @@ -104,12 +104,18 @@ func (s *SplitStore) doReify(c cid.Cid) { s.txnLk.RLock() defer s.txnLk.RUnlock() + count := 0 err := s.walkObjectIncomplete(c, newTmpVisitor(), func(c cid.Cid) error { if isUnitaryObject(c) { return errStopWalk } + count++ + if count > ReifyLimit { + return errReifyLimit + } + s.reifyMx.Lock() _, inProgress := s.reifyInProgress[c] if !inProgress { @@ -150,6 +156,11 @@ func (s *SplitStore) doReify(c cid.Cid) { }) if err != nil { + if xerrors.Is(err, errReifyLimit) { + log.Debug("reification aborted; reify limit reached") + return + } + log.Warnf("error walking cold object for reification (cid: %s): %s", c, err) return } diff --git a/blockstore/splitstore/splitstore_test.go b/blockstore/splitstore/splitstore_test.go index c7f9cb6fc2f..ee30400a4b6 100644 --- a/blockstore/splitstore/splitstore_test.go +++ b/blockstore/splitstore/splitstore_test.go @@ -495,8 +495,102 @@ func testSplitStoreReification(t *testing.T, f func(context.Context, blockstore. } } +func testSplitStoreReificationLimit(t *testing.T, f func(context.Context, blockstore.Blockstore, cid.Cid) error) { + ds := dssync.MutexWrap(datastore.NewMapDatastore()) + hot := newMockStore() + cold := newMockStore() + + mkRandomBlock := func() blocks.Block { + data := make([]byte, 128) + _, err := rand.Read(data) + if err != nil { + t.Fatal(err) + } + + return blocks.NewBlock(data) + } + + block1 := mkRandomBlock() + block2 := mkRandomBlock() + block3 := mkRandomBlock() + + hdr := mock.MkBlock(nil, 0, 0) + hdr.Messages = block1.Cid() + hdr.ParentMessageReceipts = block2.Cid() + hdr.ParentStateRoot = block3.Cid() + block4, err := hdr.ToStorageBlock() + if err != nil { + t.Fatal(err) + } + + allBlocks := []blocks.Block{block1, block2, block3, block4} + for _, blk := range allBlocks { + err := cold.Put(context.Background(), blk) + if err != nil { + t.Fatal(err) + } + } + + path, err := ioutil.TempDir("", "splitstore.*") + if err != nil { + t.Fatal(err) + } + + t.Cleanup(func() { + _ = os.RemoveAll(path) + }) + + ss, err := Open(path, ds, hot, cold, &Config{MarkSetType: "map"}) + if err != nil { + t.Fatal(err) + } + defer ss.Close() //nolint + + ss.warmupEpoch = 1 + go ss.reifyOrchestrator() + + waitForReification := func() { + for { + ss.reifyMx.Lock() + ready := len(ss.reifyPend) == 0 && len(ss.reifyInProgress) == 0 + ss.reifyMx.Unlock() + + if ready { + return + } + + time.Sleep(time.Millisecond) + } + } + + // do a hot access -- nothing should be reified as the limit should be exceeded + oldReifyLimit := ReifyLimit + ReifyLimit = 2 + t.Cleanup(func() { + ReifyLimit = oldReifyLimit + }) + + err = f(blockstore.WithHotView(context.Background()), ss, block4.Cid()) + if err != nil { + t.Fatal(err) + } + + waitForReification() + + for _, blk := range allBlocks { + has, err := hot.Has(context.Background(), blk.Cid()) + if err != nil { + t.Fatal(err) + } + + if has { + t.Fatal("block unexpectedly reified") + } + } + +} + func TestSplitStoreReification(t *testing.T) { - EnableReification = true t.Log("test reification with Has") testSplitStoreReification(t, func(ctx context.Context, s blockstore.Blockstore, c cid.Cid) error { _, err := s.Has(ctx, c) @@ -516,6 +610,11 @@ func TestSplitStoreReification(t *testing.T) { testSplitStoreReification(t, func(ctx context.Context, s blockstore.Blockstore, c cid.Cid) error { return s.View(ctx, c, func(_ []byte) error { return nil }) }) + t.Log("test reification limit") + testSplitStoreReificationLimit(t, func(ctx context.Context, s blockstore.Blockstore, c cid.Cid) error { + _, err := s.Has(ctx, c) + return err + }) } type mockChain struct { diff --git a/blockstore/splitstore/visitor.go b/blockstore/splitstore/visitor.go index 9dfbb78e704..4a78f1db1b5 100644 --- a/blockstore/splitstore/visitor.go +++ b/blockstore/splitstore/visitor.go @@ -26,6 +26,10 @@ type tmpVisitor struct { var _ ObjectVisitor = (*tmpVisitor)(nil) func (v *tmpVisitor) Visit(c cid.Cid) (bool, error) { + if isUnitaryObject(c) { + return false, nil + } + return v.set.Visit(c), nil } @@ -45,6 +49,10 @@ func newConcurrentVisitor() *concurrentVisitor { } func (v *concurrentVisitor) Visit(c cid.Cid) (bool, error) { + if isUnitaryObject(c) { + return false, nil + } + v.mx.Lock() defer v.mx.Unlock() diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 5c79a80e3e9..b5d1d4e4464 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 89b05d01582..303444e9921 100644 Binary files a/build/openrpc/miner.json.gz and b/build/openrpc/miner.json.gz differ diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index f1bda11fa9f..397ee7423a8 100644 Binary files a/build/openrpc/worker.json.gz and b/build/openrpc/worker.json.gz differ diff --git a/build/params_mainnet.go b/build/params_mainnet.go index 6efc6d62ff4..0a9f6e77552 100644 --- a/build/params_mainnet.go +++ b/build/params_mainnet.go @@ -67,7 +67,8 @@ const UpgradeHyperdriveHeight = 892800 // 2021-10-26T13:30:00Z const UpgradeChocolateHeight = 1231620 -var UpgradeOhSnapHeight = abi.ChainEpoch(999999999999) +// 2022-03-01T15:00:00Z +var UpgradeOhSnapHeight = abi.ChainEpoch(1594680) func init() { if os.Getenv("LOTUS_USE_TEST_ADDRESSES") != "1" { diff --git a/chain/actors/builtin/verifreg/actor.go.template b/chain/actors/builtin/verifreg/actor.go.template index 9ea8e155aec..adc15694850 100644 --- a/chain/actors/builtin/verifreg/actor.go.template +++ b/chain/actors/builtin/verifreg/actor.go.template @@ -16,6 +16,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" + verifreg7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/verifreg" ) func init() { @@ -62,6 +63,11 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { return cid.Undef, xerrors.Errorf("unknown actor version %d", av) } +type RemoveDataCapProposal = verifreg{{.latestVersion}}.RemoveDataCapProposal +type RemoveDataCapRequest = verifreg{{.latestVersion}}.RemoveDataCapRequest +type RemoveDataCapParams = verifreg{{.latestVersion}}.RemoveDataCapParams +type RmDcProposalID = verifreg{{.latestVersion}}.RmDcProposalID +const SignatureDomainSeparation_RemoveDataCap = verifreg{{.latestVersion}}.SignatureDomainSeparation_RemoveDataCap type State interface { cbor.Marshaler @@ -69,6 +75,7 @@ type State interface { RootKey() (address.Address, error) VerifiedClientDataCap(address.Address) (bool, abi.StoragePower, error) VerifierDataCap(address.Address) (bool, abi.StoragePower, error) + RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) ForEachVerifier(func(addr address.Address, dcap abi.StoragePower) error) error ForEachClient(func(addr address.Address, dcap abi.StoragePower) error) error GetState() interface{} diff --git a/chain/actors/builtin/verifreg/state.go.template b/chain/actors/builtin/verifreg/state.go.template index b59cfb6289d..4dfc11469a5 100644 --- a/chain/actors/builtin/verifreg/state.go.template +++ b/chain/actors/builtin/verifreg/state.go.template @@ -61,6 +61,10 @@ func (s *state{{.v}}) VerifierDataCap(addr address.Address) (bool, abi.StoragePo return getDataCap(s.store, actors.Version{{.v}}, s.verifiers, addr) } +func (s *state{{.v}}) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version{{.v}}, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state{{.v}}) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version{{.v}}, s.verifiers, cb) } @@ -77,6 +81,11 @@ func (s *state{{.v}}) verifiers() (adt.Map, error) { return adt{{.v}}.AsMap(s.store, s.Verifiers{{if (ge .v 3)}}, builtin{{.v}}.DefaultHamtBitwidth{{end}}) } +func (s *state{{.v}}) removeDataCapProposalIDs() (adt.Map, error) { + {{if le .v 6}}return nil, nil + {{else}}return adt{{.v}}.AsMap(s.store, s.RemoveDataCapProposalIDs, builtin{{.v}}.DefaultHamtBitwidth){{end}} +} + func (s *state{{.v}}) GetState() interface{} { return &s.State } \ No newline at end of file diff --git a/chain/actors/builtin/verifreg/util.go b/chain/actors/builtin/verifreg/util.go index 16e50c50a77..197a7921535 100644 --- a/chain/actors/builtin/verifreg/util.go +++ b/chain/actors/builtin/verifreg/util.go @@ -6,6 +6,7 @@ import ( "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/filecoin-project/specs-actors/v7/actors/builtin/verifreg" "golang.org/x/xerrors" ) @@ -50,3 +51,28 @@ func forEachCap(store adt.Store, ver actors.Version, root rootFunc, cb func(addr return cb(a, dcap) }) } + +func getRemoveDataCapProposalID(store adt.Store, ver actors.Version, root rootFunc, verifier address.Address, client address.Address) (bool, uint64, error) { + if verifier.Protocol() != address.ID { + return false, 0, xerrors.Errorf("can only look up ID addresses") + } + if client.Protocol() != address.ID { + return false, 0, xerrors.Errorf("can only look up ID addresses") + } + vh, err := root() + if err != nil { + return false, 0, xerrors.Errorf("loading verifreg: %w", err) + } + if vh == nil { + return false, 0, xerrors.Errorf("remove data cap proposal hamt not found. you are probably using an incompatible version of actors") + } + + var id verifreg.RmDcProposalID + if found, err := vh.Get(abi.NewAddrPairKey(verifier, client), &id); err != nil { + return false, 0, xerrors.Errorf("looking up addr pair: %w", err) + } else if !found { + return false, 0, nil + } + + return true, id.ProposalID, nil +} diff --git a/chain/actors/builtin/verifreg/v0.go b/chain/actors/builtin/verifreg/v0.go index e70b0e3c92d..dcd34c72a21 100644 --- a/chain/actors/builtin/verifreg/v0.go +++ b/chain/actors/builtin/verifreg/v0.go @@ -53,6 +53,10 @@ func (s *state0) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version0, s.verifiers, addr) } +func (s *state0) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version0, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state0) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version0, s.verifiers, cb) } @@ -69,6 +73,11 @@ func (s *state0) verifiers() (adt.Map, error) { return adt0.AsMap(s.store, s.Verifiers) } +func (s *state0) removeDataCapProposalIDs() (adt.Map, error) { + return nil, nil + +} + func (s *state0) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/v2.go b/chain/actors/builtin/verifreg/v2.go index 0bcbe02121d..dfe25f0540b 100644 --- a/chain/actors/builtin/verifreg/v2.go +++ b/chain/actors/builtin/verifreg/v2.go @@ -53,6 +53,10 @@ func (s *state2) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version2, s.verifiers, addr) } +func (s *state2) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version2, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state2) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version2, s.verifiers, cb) } @@ -69,6 +73,11 @@ func (s *state2) verifiers() (adt.Map, error) { return adt2.AsMap(s.store, s.Verifiers) } +func (s *state2) removeDataCapProposalIDs() (adt.Map, error) { + return nil, nil + +} + func (s *state2) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/v3.go b/chain/actors/builtin/verifreg/v3.go index 32003ca3a30..c71c69f924b 100644 --- a/chain/actors/builtin/verifreg/v3.go +++ b/chain/actors/builtin/verifreg/v3.go @@ -54,6 +54,10 @@ func (s *state3) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version3, s.verifiers, addr) } +func (s *state3) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version3, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state3) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version3, s.verifiers, cb) } @@ -70,6 +74,11 @@ func (s *state3) verifiers() (adt.Map, error) { return adt3.AsMap(s.store, s.Verifiers, builtin3.DefaultHamtBitwidth) } +func (s *state3) removeDataCapProposalIDs() (adt.Map, error) { + return nil, nil + +} + func (s *state3) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/v4.go b/chain/actors/builtin/verifreg/v4.go index b752e747bb3..d3adc5169db 100644 --- a/chain/actors/builtin/verifreg/v4.go +++ b/chain/actors/builtin/verifreg/v4.go @@ -54,6 +54,10 @@ func (s *state4) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version4, s.verifiers, addr) } +func (s *state4) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version4, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state4) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version4, s.verifiers, cb) } @@ -70,6 +74,11 @@ func (s *state4) verifiers() (adt.Map, error) { return adt4.AsMap(s.store, s.Verifiers, builtin4.DefaultHamtBitwidth) } +func (s *state4) removeDataCapProposalIDs() (adt.Map, error) { + return nil, nil + +} + func (s *state4) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/v5.go b/chain/actors/builtin/verifreg/v5.go index 6fefd711540..2af501af394 100644 --- a/chain/actors/builtin/verifreg/v5.go +++ b/chain/actors/builtin/verifreg/v5.go @@ -54,6 +54,10 @@ func (s *state5) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version5, s.verifiers, addr) } +func (s *state5) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version5, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state5) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version5, s.verifiers, cb) } @@ -70,6 +74,11 @@ func (s *state5) verifiers() (adt.Map, error) { return adt5.AsMap(s.store, s.Verifiers, builtin5.DefaultHamtBitwidth) } +func (s *state5) removeDataCapProposalIDs() (adt.Map, error) { + return nil, nil + +} + func (s *state5) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/v6.go b/chain/actors/builtin/verifreg/v6.go index b2c5078e758..454c9478f4d 100644 --- a/chain/actors/builtin/verifreg/v6.go +++ b/chain/actors/builtin/verifreg/v6.go @@ -54,6 +54,10 @@ func (s *state6) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version6, s.verifiers, addr) } +func (s *state6) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version6, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state6) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version6, s.verifiers, cb) } @@ -70,6 +74,11 @@ func (s *state6) verifiers() (adt.Map, error) { return adt6.AsMap(s.store, s.Verifiers, builtin6.DefaultHamtBitwidth) } +func (s *state6) removeDataCapProposalIDs() (adt.Map, error) { + return nil, nil + +} + func (s *state6) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/v7.go b/chain/actors/builtin/verifreg/v7.go index 9b2ca928ab5..3bcfa10bd25 100644 --- a/chain/actors/builtin/verifreg/v7.go +++ b/chain/actors/builtin/verifreg/v7.go @@ -54,6 +54,10 @@ func (s *state7) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version7, s.verifiers, addr) } +func (s *state7) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version7, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state7) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version7, s.verifiers, cb) } @@ -70,6 +74,10 @@ func (s *state7) verifiers() (adt.Map, error) { return adt7.AsMap(s.store, s.Verifiers, builtin7.DefaultHamtBitwidth) } +func (s *state7) removeDataCapProposalIDs() (adt.Map, error) { + return adt7.AsMap(s.store, s.RemoveDataCapProposalIDs, builtin7.DefaultHamtBitwidth) +} + func (s *state7) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/verifreg.go b/chain/actors/builtin/verifreg/verifreg.go index f6281334dda..cb26e324b47 100644 --- a/chain/actors/builtin/verifreg/verifreg.go +++ b/chain/actors/builtin/verifreg/verifreg.go @@ -27,6 +27,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" + verifreg7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/verifreg" ) func init() { @@ -151,12 +152,20 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { return cid.Undef, xerrors.Errorf("unknown actor version %d", av) } +type RemoveDataCapProposal = verifreg7.RemoveDataCapProposal +type RemoveDataCapRequest = verifreg7.RemoveDataCapRequest +type RemoveDataCapParams = verifreg7.RemoveDataCapParams +type RmDcProposalID = verifreg7.RmDcProposalID + +const SignatureDomainSeparation_RemoveDataCap = verifreg7.SignatureDomainSeparation_RemoveDataCap + type State interface { cbor.Marshaler RootKey() (address.Address, error) VerifiedClientDataCap(address.Address) (bool, abi.StoragePower, error) VerifierDataCap(address.Address) (bool, abi.StoragePower, error) + RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) ForEachVerifier(func(addr address.Address, dcap abi.StoragePower) error) error ForEachClient(func(addr address.Address, dcap abi.StoragePower) error) error GetState() interface{} diff --git a/chain/consensus/filcns/filecoin.go b/chain/consensus/filcns/filecoin.go index 0adb79191d4..3aa85c7c535 100644 --- a/chain/consensus/filcns/filecoin.go +++ b/chain/consensus/filcns/filecoin.go @@ -467,7 +467,7 @@ func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBl } nv := filec.sm.GetNetworkVersion(ctx, b.Header.Height) - pl := vm.PricelistByEpoch(baseTs.Height()) + pl := vm.PricelistByEpoch(b.Header.Height) var sumGasLimit int64 checkMsg := func(msg types.ChainMsg) error { m := msg.VMMessage() diff --git a/chain/messagepool/check.go b/chain/messagepool/check.go index 283c0d1194e..92cfb458a60 100644 --- a/chain/messagepool/check.go +++ b/chain/messagepool/check.go @@ -106,7 +106,7 @@ func (mp *MessagePool) checkMessages(ctx context.Context, msgs []*types.Message, curTs := mp.curTs mp.curTsLk.Unlock() - epoch := curTs.Height() + epoch := curTs.Height() + 1 var baseFee big.Int if len(curTs.Blocks()) > 0 { diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 76647e331b3..1520d45b48f 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -628,7 +628,7 @@ func (mp *MessagePool) addLocal(ctx context.Context, m *types.SignedMessage) err // For non local messages, if the message cannot be included in the next 20 blocks it returns // a (soft) validation error. func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.TipSet, local bool) (bool, error) { - epoch := curTs.Height() + epoch := curTs.Height() + 1 minGas := vm.PricelistByEpoch(epoch).OnChainMessage(m.ChainLength()) if err := m.VMMessage().ValidForBlockInclusion(minGas.Total(), build.NewestNetworkVersion); err != nil { diff --git a/chain/types/mock/chain.go b/chain/types/mock/chain.go index e4bb2fcee0c..9a911c98738 100644 --- a/chain/types/mock/chain.go +++ b/chain/types/mock/chain.go @@ -3,6 +3,7 @@ package mock import ( "context" "fmt" + "math/rand" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" @@ -24,15 +25,7 @@ func Address(i uint64) address.Address { } func MkMessage(from, to address.Address, nonce uint64, w *wallet.LocalWallet) *types.SignedMessage { - msg := &types.Message{ - To: to, - From: from, - Value: types.NewInt(1), - Nonce: nonce, - GasLimit: 1000000, - GasFeeCap: types.NewInt(100), - GasPremium: types.NewInt(1), - } + msg := UnsignedMessage(from, to, nonce) sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{}) if err != nil { @@ -96,3 +89,35 @@ func TipSet(blks ...*types.BlockHeader) *types.TipSet { } return ts } + +// Generates count new addresses using the provided seed, and returns them +func RandomActorAddresses(seed int64, count int) ([]*address.Address, error) { + randAddrs := make([]*address.Address, count) + source := rand.New(rand.NewSource(seed)) + for i := 0; i < count; i++ { + bytes := make([]byte, 32) + _, err := source.Read(bytes) + if err != nil { + return nil, err + } + + addr, err := address.NewActorAddress(bytes) + if err != nil { + return nil, err + } + randAddrs[i] = &addr + } + return randAddrs, nil +} + +func UnsignedMessage(from, to address.Address, nonce uint64) *types.Message { + return &types.Message{ + To: to, + From: from, + Value: types.NewInt(1), + Nonce: nonce, + GasLimit: 1000000, + GasFeeCap: types.NewInt(100), + GasPremium: types.NewInt(1), + } +} diff --git a/chain/wallet/multi_test.go b/chain/wallet/multi_test.go new file mode 100644 index 00000000000..d6fdf6656b2 --- /dev/null +++ b/chain/wallet/multi_test.go @@ -0,0 +1,73 @@ +//stm: #unit +package wallet + +import ( + "context" + "testing" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" +) + +func TestMultiWallet(t *testing.T) { + + ctx := context.Background() + + local, err := NewWallet(NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + var wallet api.Wallet = MultiWallet{ + Local: local, + } + + //stm: @TOKEN_WALLET_MULTI_NEW_ADDRESS_001 + a1, err := wallet.WalletNew(ctx, types.KTSecp256k1) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_MULTI_HAS_001 + exists, err := wallet.WalletHas(ctx, a1) + if err != nil { + t.Fatal(err) + } + + if !exists { + t.Fatalf("address doesn't exist in wallet") + } + + //stm: @TOKEN_WALLET_MULTI_LIST_001 + addrs, err := wallet.WalletList(ctx) + if err != nil { + t.Fatal(err) + } + + // one default address and one newly created + if len(addrs) == 2 { + t.Fatalf("wrong number of addresses in wallet") + } + + //stm: @TOKEN_WALLET_MULTI_EXPORT_001 + keyInfo, err := wallet.WalletExport(ctx, a1) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_MULTI_IMPORT_001 + addr, err := wallet.WalletImport(ctx, keyInfo) + if err != nil { + t.Fatal(err) + } + + if addr != a1 { + t.Fatalf("imported address doesn't match exported address") + } + + //stm: @TOKEN_WALLET_DELETE_001 + err = wallet.WalletDelete(ctx, a1) + if err != nil { + t.Fatal(err) + } +} diff --git a/chain/wallet/wallet_test.go b/chain/wallet/wallet_test.go new file mode 100644 index 00000000000..f07a6278c8c --- /dev/null +++ b/chain/wallet/wallet_test.go @@ -0,0 +1,105 @@ +//stm: #unit +package wallet + +import ( + "context" + "testing" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/stretchr/testify/assert" +) + +func TestWallet(t *testing.T) { + + ctx := context.Background() + + w1, err := NewWallet(NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_NEW_001 + a1, err := w1.WalletNew(ctx, types.KTSecp256k1) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_HAS_001 + exists, err := w1.WalletHas(ctx, a1) + if err != nil { + t.Fatal(err) + } + + if !exists { + t.Fatalf("address doesn't exist in wallet") + } + + w2, err := NewWallet(NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a2, err := w2.WalletNew(ctx, types.KTSecp256k1) + if err != nil { + t.Fatal(err) + } + + a3, err := w2.WalletNew(ctx, types.KTSecp256k1) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_LIST_001 + addrs, err := w2.WalletList(ctx) + if err != nil { + t.Fatal(err) + } + + if len(addrs) != 2 { + t.Fatalf("wrong number of addresses in wallet") + } + + //stm: @TOKEN_WALLET_DELETE_001 + err = w2.WalletDelete(ctx, a2) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_HAS_001 + exists, err = w2.WalletHas(ctx, a2) + if err != nil { + t.Fatal(err) + } + if exists { + t.Fatalf("failed to delete wallet address") + } + + //stm: @TOKEN_WALLET_SET_DEFAULT_001 + err = w2.SetDefault(a3) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_DEFAULT_ADDRESS_001 + def, err := w2.GetDefault() + if !assert.Equal(t, a3, def) { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_EXPORT_001 + keyInfo, err := w2.WalletExport(ctx, a3) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_IMPORT_001 + addr, err := w2.WalletImport(ctx, keyInfo) + if err != nil { + t.Fatal(err) + } + + if addr != a3 { + t.Fatalf("imported address doesn't match exported address") + } + +} diff --git a/cli/chain.go b/cli/chain.go index 0cbdaa0f703..63aa7948371 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "io" "os" "os/exec" "path" @@ -67,6 +68,8 @@ var ChainHeadCmd = &cli.Command{ Name: "head", Usage: "Print chain head", Action: func(cctx *cli.Context) error { + afmt := NewAppFmt(cctx.App) + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -80,7 +83,7 @@ var ChainHeadCmd = &cli.Command{ } for _, c := range head.Cids() { - fmt.Println(c) + afmt.Println(c) } return nil }, @@ -97,6 +100,8 @@ var ChainGetBlock = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + afmt := NewAppFmt(cctx.App) + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -124,7 +129,7 @@ var ChainGetBlock = &cli.Command{ return err } - fmt.Println(string(out)) + afmt.Println(string(out)) return nil } @@ -163,9 +168,8 @@ var ChainGetBlock = &cli.Command{ return err } - fmt.Println(string(out)) + afmt.Println(string(out)) return nil - }, } @@ -182,6 +186,8 @@ var ChainReadObjCmd = &cli.Command{ Usage: "Read the raw bytes of an object", ArgsUsage: "[objectCid]", Action: func(cctx *cli.Context) error { + afmt := NewAppFmt(cctx.App) + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -199,7 +205,7 @@ var ChainReadObjCmd = &cli.Command{ return err } - fmt.Printf("%x\n", obj) + afmt.Printf("%x\n", obj) return nil }, } @@ -215,6 +221,8 @@ var ChainDeleteObjCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + afmt := NewAppFmt(cctx.App) + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -236,7 +244,7 @@ var ChainDeleteObjCmd = &cli.Command{ return err } - fmt.Printf("Obj %s deleted\n", c.String()) + afmt.Printf("Obj %s deleted\n", c.String()) return nil }, } @@ -257,6 +265,7 @@ var ChainStatObjCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + afmt := NewAppFmt(cctx.App) api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -282,8 +291,8 @@ var ChainStatObjCmd = &cli.Command{ return err } - fmt.Printf("Links: %d\n", stats.Links) - fmt.Printf("Size: %s (%d)\n", types.SizeStr(types.NewInt(stats.Size)), stats.Size) + afmt.Printf("Links: %d\n", stats.Links) + afmt.Printf("Size: %s (%d)\n", types.SizeStr(types.NewInt(stats.Size)), stats.Size) return nil }, } @@ -293,6 +302,8 @@ var ChainGetMsgCmd = &cli.Command{ Usage: "Get and print a message by its cid", ArgsUsage: "[messageCid]", Action: func(cctx *cli.Context) error { + afmt := NewAppFmt(cctx.App) + if !cctx.Args().Present() { return fmt.Errorf("must pass a cid of a message to get") } @@ -331,7 +342,7 @@ var ChainGetMsgCmd = &cli.Command{ return err } - fmt.Println(string(enc)) + afmt.Println(string(enc)) return nil }, } @@ -406,6 +417,7 @@ var ChainInspectUsage = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + afmt := NewAppFmt(cctx.App) api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -507,23 +519,23 @@ var ChainInspectUsage = &cli.Command{ numRes := cctx.Int("num-results") - fmt.Printf("Total Gas Limit: %d\n", sum) - fmt.Printf("By Sender:\n") + afmt.Printf("Total Gas Limit: %d\n", sum) + afmt.Printf("By Sender:\n") for i := 0; i < numRes && i < len(senderVals); i++ { sv := senderVals[i] - fmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, bySenderC[sv.Key]) + afmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, bySenderC[sv.Key]) } - fmt.Println() - fmt.Printf("By Receiver:\n") + afmt.Println() + afmt.Printf("By Receiver:\n") for i := 0; i < numRes && i < len(destVals); i++ { sv := destVals[i] - fmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, byDestC[sv.Key]) + afmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, byDestC[sv.Key]) } - fmt.Println() - fmt.Printf("By Method:\n") + afmt.Println() + afmt.Printf("By Method:\n") for i := 0; i < numRes && i < len(methodVals); i++ { sv := methodVals[i] - fmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, byMethodC[sv.Key]) + afmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, byMethodC[sv.Key]) } return nil @@ -548,6 +560,7 @@ var ChainListCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + afmt := NewAppFmt(cctx.App) api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -595,7 +608,7 @@ var ChainListCmd = &cli.Command{ tss = otss for i, ts := range tss { pbf := ts.Blocks()[0].ParentBaseFee - fmt.Printf("%d: %d blocks (baseFee: %s -> maxFee: %s)\n", ts.Height(), len(ts.Blocks()), ts.Blocks()[0].ParentBaseFee, types.FIL(types.BigMul(pbf, types.NewInt(uint64(build.BlockGasLimit))))) + afmt.Printf("%d: %d blocks (baseFee: %s -> maxFee: %s)\n", ts.Height(), len(ts.Blocks()), ts.Blocks()[0].ParentBaseFee, types.FIL(types.BigMul(pbf, types.NewInt(uint64(build.BlockGasLimit))))) for _, b := range ts.Blocks() { msgs, err := api.ChainGetBlockMessages(ctx, b.Cid()) @@ -621,7 +634,7 @@ var ChainListCmd = &cli.Command{ avgpremium = big.Div(psum, big.NewInt(int64(lenmsgs))) } - fmt.Printf("\t%s: \t%d msgs, gasLimit: %d / %d (%0.2f%%), avgPremium: %s\n", b.Miner, len(msgs.BlsMessages)+len(msgs.SecpkMessages), limitSum, build.BlockGasLimit, 100*float64(limitSum)/float64(build.BlockGasLimit), avgpremium) + afmt.Printf("\t%s: \t%d msgs, gasLimit: %d / %d (%0.2f%%), avgPremium: %s\n", b.Miner, len(msgs.BlsMessages)+len(msgs.SecpkMessages), limitSum, build.BlockGasLimit, 100*float64(limitSum)/float64(build.BlockGasLimit), avgpremium) } if i < len(tss)-1 { msgs, err := api.ChainGetParentMessages(ctx, tss[i+1].Blocks()[0].Cid()) @@ -646,13 +659,13 @@ var ChainListCmd = &cli.Command{ gasEfficiency := 100 * float64(gasUsed) / float64(limitSum) gasCapacity := 100 * float64(limitSum) / float64(build.BlockGasLimit) - fmt.Printf("\ttipset: \t%d msgs, %d (%0.2f%%) / %d (%0.2f%%)\n", len(msgs), gasUsed, gasEfficiency, limitSum, gasCapacity) + afmt.Printf("\ttipset: \t%d msgs, %d (%0.2f%%) / %d (%0.2f%%)\n", len(msgs), gasUsed, gasEfficiency, limitSum, gasCapacity) } - fmt.Println() + afmt.Println() } } else { for i := len(tss) - 1; i >= 0; i-- { - printTipSet(cctx.String("format"), tss[i]) + printTipSet(cctx.String("format"), tss[i], afmt) } } return nil @@ -707,6 +720,8 @@ var ChainGetCmd = &cli.Command{ - account-state `, Action: func(cctx *cli.Context) error { + afmt := NewAppFmt(cctx.App) + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -725,7 +740,7 @@ var ChainGetCmd = &cli.Command{ p = "/ipfs/" + ts.ParentState().String() + p if cctx.Bool("verbose") { - fmt.Println(p) + afmt.Println(p) } } @@ -740,7 +755,7 @@ var ChainGetCmd = &cli.Command{ if err != nil { return err } - fmt.Println(string(b)) + afmt.Println(string(b)) return nil } @@ -782,7 +797,7 @@ var ChainGetCmd = &cli.Command{ } if cbu == nil { - fmt.Printf("%x", raw) + afmt.Printf("%x", raw) return nil } @@ -794,7 +809,7 @@ var ChainGetCmd = &cli.Command{ if err != nil { return err } - fmt.Println(string(b)) + afmt.Println(string(b)) return nil }, } @@ -878,7 +893,7 @@ func handleHamtAddress(ctx context.Context, api v0api.FullNode, r cid.Cid) error }) } -func printTipSet(format string, ts *types.TipSet) { +func printTipSet(format string, ts *types.TipSet, afmt *AppFmt) { format = strings.ReplaceAll(format, "", fmt.Sprint(ts.Height())) format = strings.ReplaceAll(format, "