diff --git a/chain/vm/gas.go b/chain/vm/gas.go index 731f0c4d5..eef431aef 100644 --- a/chain/vm/gas.go +++ b/chain/vm/gas.go @@ -3,21 +3,17 @@ package vm import ( "fmt" - vmr2 "github.com/filecoin-project/specs-actors/v2/actors/runtime" - proof2 "github.com/filecoin-project/specs-actors/v2/actors/runtime/proof" + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/go-address" addr "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" + vmr2 "github.com/filecoin-project/specs-actors/v2/actors/runtime" + proof2 "github.com/filecoin-project/specs-actors/v2/actors/runtime/proof" "github.com/ipfs/go-cid" ) -const ( - GasStorageMulti = 1000 - GasComputeMulti = 1 -) - type GasCharge struct { Name string Extra interface{} @@ -132,6 +128,54 @@ var prices = map[abi.ChainEpoch]Pricelist{ verifyPostDiscount: true, verifyConsensusFault: 495422, }, + abi.ChainEpoch(build.UpgradeCalicoHeight): &pricelistV0{ + computeGasMulti: 1, + storageGasMulti: 1300, + + onChainMessageComputeBase: 38863, + onChainMessageStorageBase: 36, + onChainMessageStoragePerByte: 1, + + onChainReturnValuePerByte: 1, + + sendBase: 29233, + sendTransferFunds: 27500, + sendTransferOnlyPremium: 159672, + sendInvokeMethod: -5377, + + ipldGetBase: 114617, + ipldPutBase: 353640, + ipldPutPerByte: 1, + + createActorCompute: 1108454, + createActorStorage: 36 + 40, + deleteActor: -(36 + 40), // -createActorStorage + + verifySignature: map[crypto.SigType]int64{ + crypto.SigTypeBLS: 16598605, + crypto.SigTypeSecp256k1: 1637292, + }, + + hashingBase: 31355, + computeUnsealedSectorCidBase: 98647, + verifySealBase: 2000, // TODO gas , it VerifySeal syscall is not used + verifyPostLookup: map[abi.RegisteredPoStProof]scalingCost{ + abi.RegisteredPoStProof_StackedDrgWindow512MiBV1: { + flat: 117680921, + scale: 43780, + }, + abi.RegisteredPoStProof_StackedDrgWindow32GiBV1: { + flat: 117680921, + scale: 43780, + }, + abi.RegisteredPoStProof_StackedDrgWindow64GiBV1: { + flat: 117680921, + scale: 43780, + }, + }, + verifyPostDiscount: false, + verifyConsensusFault: 495422, + }, } // PricelistByEpoch finds the latest prices for the given epoch diff --git a/chain/vm/gas_v0.go b/chain/vm/gas_v0.go index df3709058..7c864b7f9 100644 --- a/chain/vm/gas_v0.go +++ b/chain/vm/gas_v0.go @@ -133,13 +133,13 @@ func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.M // OnIpldGet returns the gas used for storing an object func (pl *pricelistV0) OnIpldGet() GasCharge { - return newGasCharge("OnIpldGet", pl.ipldGetBase, 0) + return newGasCharge("OnIpldGet", pl.ipldGetBase, 0).WithVirtual(114617, 0) } // OnIpldPut returns the gas used for storing an object func (pl *pricelistV0) OnIpldPut(dataSize int) GasCharge { return newGasCharge("OnIpldPut", pl.ipldPutBase, int64(dataSize)*pl.ipldPutPerByte*pl.storageGasMulti). - WithExtra(dataSize) + WithExtra(dataSize).WithVirtual(400000, int64(dataSize)*1300) } // OnCreateActor returns the gas used for creating an actor @@ -209,6 +209,7 @@ func (pl *pricelistV0) OnVerifyPost(info proof2.WindowPoStVerifyInfo) GasCharge } return newGasCharge("OnVerifyPost", gasUsed, 0). + WithVirtual(117680921+43780*int64(len(info.ChallengedSectors)), 0). WithExtra(map[string]interface{}{ "type": sectorSize, "size": len(info.ChallengedSectors), diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 9107e6d7e..ef69ca103 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -539,12 +539,19 @@ func (rt *Runtime) chargeGasInternal(gas GasCharge, skip int) aerrors.ActorError ComputeGas: gas.ComputeGas, StorageGas: gas.StorageGas, - TotalVirtualGas: gas.VirtualCompute*GasComputeMulti + gas.VirtualStorage*GasStorageMulti, VirtualComputeGas: gas.VirtualCompute, VirtualStorageGas: gas.VirtualStorage, Callers: callers[:cout], } + if gasTrace.VirtualStorageGas == 0 { + gasTrace.VirtualStorageGas = gasTrace.StorageGas + } + if gasTrace.VirtualComputeGas == 0 { + gasTrace.VirtualComputeGas = gasTrace.ComputeGas + } + gasTrace.TotalVirtualGas = gasTrace.VirtualComputeGas + gasTrace.VirtualStorageGas + rt.executionTrace.GasCharges = append(rt.executionTrace.GasCharges, &gasTrace) rt.lastGasChargeTime = now rt.lastGasCharge = &gasTrace diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 5f82b9669..0919b8e8a 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -9,6 +9,7 @@ import ( "time" "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/metrics" block "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" @@ -16,6 +17,7 @@ import ( logging "github.com/ipfs/go-log/v2" mh "github.com/multiformats/go-multihash" cbg "github.com/whyrusleeping/cbor-gen" + "go.opencensus.io/stats" "go.opencensus.io/trace" "golang.org/x/xerrors" @@ -606,6 +608,8 @@ func (vm *VM) ActorBalance(addr address.Address) (types.BigInt, aerrors.ActorErr return act.Balance, nil } +type vmFlushKey struct{} + func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) { _, span := trace.StartSpan(ctx, "vm.Flush") defer span.End() @@ -618,7 +622,7 @@ func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) { return cid.Undef, xerrors.Errorf("flushing vm: %w", err) } - if err := Copy(ctx, from, to, root); err != nil { + if err := Copy(context.WithValue(ctx, vmFlushKey{}, true), from, to, root); err != nil { return cid.Undef, xerrors.Errorf("copying tree: %w", err) } @@ -675,21 +679,48 @@ func linksForObj(blk block.Block, cb func(cid.Cid)) error { func Copy(ctx context.Context, from, to blockstore.Blockstore, root cid.Cid) error { ctx, span := trace.StartSpan(ctx, "vm.Copy") // nolint defer span.End() + start := time.Now() var numBlocks int var totalCopySize int - var batch []block.Block + const batchSize = 128 + const bufCount = 3 + freeBufs := make(chan []block.Block, bufCount) + toFlush := make(chan []block.Block, bufCount) + for i := 0; i < bufCount; i++ { + freeBufs <- make([]block.Block, 0, batchSize) + } + + errFlushChan := make(chan error) + + go func() { + for b := range toFlush { + if err := to.PutMany(b); err != nil { + close(freeBufs) + errFlushChan <- xerrors.Errorf("batch put in copy: %w", err) + return + } + freeBufs <- b[:0] + } + close(errFlushChan) + close(freeBufs) + }() + + var batch = <-freeBufs batchCp := func(blk block.Block) error { numBlocks++ totalCopySize += len(blk.RawData()) batch = append(batch, blk) - if len(batch) > 100 { - if err := to.PutMany(batch); err != nil { - return xerrors.Errorf("batch put in copy: %w", err) + + if len(batch) >= batchSize { + toFlush <- batch + var ok bool + batch, ok = <-freeBufs + if !ok { + return <-errFlushChan } - batch = batch[:0] } return nil } @@ -699,15 +730,22 @@ func Copy(ctx context.Context, from, to blockstore.Blockstore, root cid.Cid) err } if len(batch) > 0 { - if err := to.PutMany(batch); err != nil { - return xerrors.Errorf("batch put in copy: %w", err) - } + toFlush <- batch + } + close(toFlush) // close the toFlush triggering the loop to end + err := <-errFlushChan // get error out or get nil if it was closed + if err != nil { + return err } span.AddAttributes( trace.Int64Attribute("numBlocks", int64(numBlocks)), trace.Int64Attribute("copySize", int64(totalCopySize)), ) + if yes, ok := ctx.Value(vmFlushKey{}).(bool); yes && ok { + took := metrics.SinceInMilliseconds(start) + stats.Record(ctx, metrics.VMFlushCopyCount.M(int64(numBlocks)), metrics.VMFlushCopyDuration.M(took)) + } return nil } diff --git a/conformance/chaos/actor.go b/conformance/chaos/actor.go index cdda1db83..f5a94989d 100644 --- a/conformance/chaos/actor.go +++ b/conformance/chaos/actor.go @@ -73,6 +73,8 @@ const ( // MethodInspectRuntime is the identifier for the method that returns the // current runtime values. MethodInspectRuntime + // MethodCreateState is the identifier for the method that creates the chaos actor's state. + MethodCreateState ) // Exports defines the methods this actor exposes publicly. @@ -87,6 +89,7 @@ func (a Actor) Exports() []interface{} { MethodMutateState: a.MutateState, MethodAbortWith: a.AbortWith, MethodInspectRuntime: a.InspectRuntime, + MethodCreateState: a.CreateState, } } @@ -227,6 +230,14 @@ type MutateStateArgs struct { Branch MutateStateBranch } +// CreateState creates the chaos actor's state +func (a Actor) CreateState(rt runtime2.Runtime, _ *abi.EmptyValue) *abi.EmptyValue { + rt.ValidateImmediateCallerAcceptAny() + rt.StateCreate(&State{}) + + return nil +} + // MutateState attempts to mutate a state value in the actor. func (a Actor) MutateState(rt runtime2.Runtime, args *MutateStateArgs) *abi.EmptyValue { rt.ValidateImmediateCallerAcceptAny() diff --git a/conformance/chaos/actor_test.go b/conformance/chaos/actor_test.go index dbce4f4c5..e68b9a4df 100644 --- a/conformance/chaos/actor_test.go +++ b/conformance/chaos/actor_test.go @@ -129,8 +129,9 @@ func TestMutateStateInTransaction(t *testing.T) { var a Actor rt.ExpectValidateCallerAny() - rt.StateCreate(&State{}) + rt.Call(a.CreateState, nil) + rt.ExpectValidateCallerAny() val := "__mutstat test" rt.Call(a.MutateState, &MutateStateArgs{ Value: val, @@ -155,23 +156,30 @@ func TestMutateStateAfterTransaction(t *testing.T) { var a Actor rt.ExpectValidateCallerAny() - rt.StateCreate(&State{}) + rt.Call(a.CreateState, nil) + rt.ExpectValidateCallerAny() val := "__mutstat test" + defer func() { + if r := recover(); r == nil { + t.Fatal("The code did not panic") + } else { + var st State + rt.GetState(&st) + + // state should be updated successfully _in_ the transaction but not outside + if st.Value != val+"-in" { + t.Fatal("state was not updated") + } + + rt.Verify() + } + }() rt.Call(a.MutateState, &MutateStateArgs{ Value: val, Branch: MutateAfterTransaction, }) - var st State - rt.GetState(&st) - - // state should be updated successfully _in_ the transaction but not outside - if st.Value != val+"-in" { - t.Fatal("state was not updated") - } - - rt.Verify() } func TestMutateStateReadonly(t *testing.T) { @@ -182,22 +190,30 @@ func TestMutateStateReadonly(t *testing.T) { var a Actor rt.ExpectValidateCallerAny() - rt.StateCreate(&State{}) + rt.Call(a.CreateState, nil) + rt.ExpectValidateCallerAny() val := "__mutstat test" + defer func() { + if r := recover(); r == nil { + t.Fatal("The code did not panic") + } else { + var st State + rt.GetState(&st) + + if st.Value != "" { + t.Fatal("state was not expected to be updated") + } + + rt.Verify() + } + }() + rt.Call(a.MutateState, &MutateStateArgs{ Value: val, Branch: MutateReadonly, }) - var st State - rt.GetState(&st) - - if st.Value != "" { - t.Fatal("state was not expected to be updated") - } - - rt.Verify() } func TestMutateStateInvalidBranch(t *testing.T) { @@ -254,11 +270,13 @@ func TestInspectRuntime(t *testing.T) { receiver := atesting2.NewIDAddr(t, 101) builder := mock2.NewBuilder(context.Background(), receiver) - rt := builder.Build(t) - rt.SetCaller(caller, builtin2.AccountActorCodeID) - rt.StateCreate(&State{}) var a Actor + rt := builder.Build(t) + rt.ExpectValidateCallerAny() + rt.Call(a.CreateState, nil) + + rt.SetCaller(caller, builtin2.AccountActorCodeID) rt.ExpectValidateCallerAny() ret := rt.Call(a.InspectRuntime, abi.Empty) rtr, ok := ret.(*InspectRuntimeReturn) diff --git a/go.mod b/go.mod index f0ffa4845..69f7cdb4c 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/filecoin-project/go-statestore v0.1.0 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b github.com/filecoin-project/specs-actors v0.9.13 - github.com/filecoin-project/specs-actors/v2 v2.3.0 + github.com/filecoin-project/specs-actors/v2 v2.3.2 github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 github.com/filecoin-project/test-vectors/schema v0.0.5 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 diff --git a/go.sum b/go.sum index 49a1cacbb..2b6548298 100644 --- a/go.sum +++ b/go.sum @@ -289,8 +289,8 @@ github.com/filecoin-project/specs-actors v0.9.12/go.mod h1:TS1AW/7LbG+615j4NsjMK github.com/filecoin-project/specs-actors v0.9.13 h1:rUEOQouefi9fuVY/2HOroROJlZbOzWYXXeIh41KF2M4= github.com/filecoin-project/specs-actors v0.9.13/go.mod h1:TS1AW/7LbG+615j4NsjMK1qlpAwaFsG9w0V2tg2gSao= github.com/filecoin-project/specs-actors/v2 v2.0.1/go.mod h1:v2NZVYinNIKA9acEMBm5wWXxqv5+frFEbekBFemYghY= -github.com/filecoin-project/specs-actors/v2 v2.3.0 h1:V7lHeF2ylfFi84F4y80u5FE4BpPHYGvB71kLrhXkJto= -github.com/filecoin-project/specs-actors/v2 v2.3.0/go.mod h1:UuJQLoTx/HPvvWeqlIFmC/ywlOLHNe8SNQ3OunFbu2Y= +github.com/filecoin-project/specs-actors/v2 v2.3.2 h1:2Vcf4CGa29kRh4JJ02m+FbvD/p3YNnLGsaHfw7Uj49g= +github.com/filecoin-project/specs-actors/v2 v2.3.2/go.mod h1:UuJQLoTx/HPvvWeqlIFmC/ywlOLHNe8SNQ3OunFbu2Y= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 h1:Ur/l2+6qN+lQiqjozWWc5p9UDaAMDZKTlDS98oRnlIw= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg= diff --git a/metrics/metrics.go b/metrics/metrics.go index 33d9e9174..9f0cad27f 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -53,6 +53,8 @@ var ( PubsubSendRPC = stats.Int64("pubsub/send_rpc", "Counter for total sent RPCs", stats.UnitDimensionless) PubsubDropRPC = stats.Int64("pubsub/drop_rpc", "Counter for total dropped RPCs", stats.UnitDimensionless) APIRequestDuration = stats.Float64("api/request_duration_ms", "Duration of API requests", stats.UnitMilliseconds) + VMFlushCopyDuration = stats.Float64("vm/flush_copy_ms", "Time spent in VM Flush Copy", stats.UnitMilliseconds) + VMFlushCopyCount = stats.Int64("vm/flush_copy_count", "Number of copied objects", stats.UnitDimensionless) ) var ( @@ -146,6 +148,14 @@ var ( Aggregation: defaultMillisecondsDistribution, TagKeys: []tag.Key{APIInterface, Endpoint}, } + VMFlushCopyDurationView = &view.View{ + Measure: VMFlushCopyDuration, + Aggregation: view.Sum(), + } + VMFlushCopyCountView = &view.View{ + Measure: VMFlushCopyCount, + Aggregation: view.Sum(), + } ) // DefaultViews is an array of OpenCensus views for metric gathering purposes @@ -171,6 +181,8 @@ var DefaultViews = append([]*view.View{ PubsubSendRPCView, PubsubDropRPCView, APIRequestDurationView, + VMFlushCopyCountView, + VMFlushCopyDurationView, }, rpcmetrics.DefaultViews...)