mirror of
https://github.com/filecoin-project/lotus.git
synced 2025-08-24 17:31:42 +08:00

This is a large diff, yet should have exactly zero functional changes Ideally as a result of this some parts of the depchain will become lighter, with downstream reaping the same benefits as the team that initiated this split. P.S. work was done while forming better intuition of current dependency graph
340 lines
10 KiB
Go
340 lines
10 KiB
Go
package vm
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/ipfs/go-cid"
|
|
|
|
"github.com/filecoin-project/go-address"
|
|
"github.com/filecoin-project/go-state-types/abi"
|
|
"github.com/filecoin-project/go-state-types/crypto"
|
|
vmr "github.com/filecoin-project/specs-actors/v7/actors/runtime"
|
|
proof7 "github.com/filecoin-project/specs-actors/v7/actors/runtime/proof"
|
|
|
|
"github.com/filecoin-project/lotus/build/buildconstants"
|
|
)
|
|
|
|
type GasCharge struct {
|
|
Name string
|
|
Extra interface{}
|
|
|
|
ComputeGas int64
|
|
StorageGas int64
|
|
|
|
VirtualCompute int64
|
|
VirtualStorage int64
|
|
}
|
|
|
|
func (g GasCharge) Total() int64 {
|
|
return g.ComputeGas + g.StorageGas
|
|
}
|
|
func (g GasCharge) WithVirtual(compute, storage int64) GasCharge {
|
|
out := g
|
|
out.VirtualCompute = compute
|
|
out.VirtualStorage = storage
|
|
return out
|
|
}
|
|
|
|
func (g GasCharge) WithExtra(extra interface{}) GasCharge {
|
|
out := g
|
|
out.Extra = extra
|
|
return out
|
|
}
|
|
|
|
func newGasCharge(name string, computeGas int64, storageGas int64) GasCharge {
|
|
return GasCharge{
|
|
Name: name,
|
|
ComputeGas: computeGas,
|
|
StorageGas: storageGas,
|
|
}
|
|
}
|
|
|
|
// Pricelist provides prices for operations in the LegacyVM.
|
|
//
|
|
// Note: this interface should be APPEND ONLY since last chain checkpoint
|
|
type Pricelist interface {
|
|
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
|
|
OnChainMessage(msgSize int) GasCharge
|
|
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
|
OnChainReturnValue(dataSize int) GasCharge
|
|
|
|
// OnMethodInvocation returns the gas used when invoking a method.
|
|
OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) GasCharge
|
|
|
|
// OnIpldGet returns the gas used for storing an object
|
|
OnIpldGet() GasCharge
|
|
// OnIpldPut returns the gas used for storing an object
|
|
OnIpldPut(dataSize int) GasCharge
|
|
|
|
// OnCreateActor returns the gas used for creating an actor
|
|
OnCreateActor() GasCharge
|
|
// OnDeleteActor returns the gas used for deleting an actor
|
|
OnDeleteActor() GasCharge
|
|
|
|
OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error)
|
|
OnHashing(dataSize int) GasCharge
|
|
OnComputeUnsealedSectorCid(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) GasCharge
|
|
OnVerifySeal(info proof7.SealVerifyInfo) GasCharge
|
|
OnVerifyAggregateSeals(aggregate proof7.AggregateSealVerifyProofAndInfos) GasCharge
|
|
OnVerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) GasCharge
|
|
OnVerifyPost(info proof7.WindowPoStVerifyInfo) GasCharge
|
|
OnVerifyConsensusFault() GasCharge
|
|
}
|
|
|
|
// Prices are the price lists per starting epoch. Public for testing purposes
|
|
// (concretely to allow the test vector runner to rebase prices).
|
|
var Prices = map[abi.ChainEpoch]Pricelist{
|
|
abi.ChainEpoch(0): &pricelistV0{
|
|
computeGasMulti: 1,
|
|
storageGasMulti: 1000,
|
|
|
|
onChainMessageComputeBase: 38863,
|
|
onChainMessageStorageBase: 36,
|
|
onChainMessageStoragePerByte: 1,
|
|
|
|
onChainReturnValuePerByte: 1,
|
|
|
|
sendBase: 29233,
|
|
sendTransferFunds: 27500,
|
|
sendTransferOnlyPremium: 159672,
|
|
sendInvokeMethod: -5377,
|
|
|
|
ipldGetBase: 75242,
|
|
ipldPutBase: 84070,
|
|
ipldPutPerByte: 1,
|
|
|
|
createActorCompute: 1108454,
|
|
createActorStorage: 36 + 40,
|
|
deleteActor: -(36 + 40), // -createActorStorage
|
|
|
|
verifySignature: map[crypto.SigType]int64{
|
|
crypto.SigTypeBLS: 16598605,
|
|
crypto.SigTypeSecp256k1: 1637292,
|
|
crypto.SigTypeDelegated: 1637292,
|
|
},
|
|
|
|
hashingBase: 31355,
|
|
computeUnsealedSectorCidBase: 98647,
|
|
verifySealBase: 2000, // TODO gas , it VerifySeal syscall is not used
|
|
verifyAggregateSealBase: 0,
|
|
verifyPostLookup: map[abi.RegisteredPoStProof]scalingCost{
|
|
abi.RegisteredPoStProof_StackedDrgWindow512MiBV1: {
|
|
flat: 123861062,
|
|
scale: 9226981,
|
|
},
|
|
abi.RegisteredPoStProof_StackedDrgWindow32GiBV1: {
|
|
flat: 748593537,
|
|
scale: 85639,
|
|
},
|
|
abi.RegisteredPoStProof_StackedDrgWindow64GiBV1: {
|
|
flat: 748593537,
|
|
scale: 85639,
|
|
},
|
|
},
|
|
verifyPostDiscount: true,
|
|
verifyConsensusFault: 495422,
|
|
},
|
|
buildconstants.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
|
|
|
|
verifyAggregateSealPer: map[abi.RegisteredSealProof]int64{
|
|
abi.RegisteredSealProof_StackedDrg32GiBV1_1: 449900,
|
|
abi.RegisteredSealProof_StackedDrg64GiBV1_1: 359272,
|
|
},
|
|
verifyAggregateSealSteps: map[abi.RegisteredSealProof]stepCost{
|
|
abi.RegisteredSealProof_StackedDrg32GiBV1_1: {
|
|
{4, 103994170},
|
|
{7, 112356810},
|
|
{13, 122912610},
|
|
{26, 137559930},
|
|
{52, 162039100},
|
|
{103, 210960780},
|
|
{205, 318351180},
|
|
{410, 528274980},
|
|
},
|
|
abi.RegisteredSealProof_StackedDrg64GiBV1_1: {
|
|
{4, 102581240},
|
|
{7, 110803030},
|
|
{13, 120803700},
|
|
{26, 134642130},
|
|
{52, 157357890},
|
|
{103, 203017690},
|
|
{205, 304253590},
|
|
{410, 509880640},
|
|
},
|
|
},
|
|
|
|
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,
|
|
|
|
verifyReplicaUpdate: 36316136,
|
|
},
|
|
buildconstants.UpgradeHyggeHeight: &pricelistV0{
|
|
computeGasMulti: 1,
|
|
storageGasMulti: 1300, // only applies to messages/return values.
|
|
|
|
onChainMessageComputeBase: 38863 + 475000, // includes the actor update cost
|
|
onChainMessageStorageBase: 36,
|
|
onChainMessageStoragePerByte: 1,
|
|
|
|
onChainReturnValuePerByte: 1,
|
|
},
|
|
}
|
|
|
|
// PricelistByEpoch finds the latest prices for the given epoch
|
|
func PricelistByEpoch(epoch abi.ChainEpoch) Pricelist {
|
|
// since we are storing the prices as map or epoch to price
|
|
// we need to get the price with the highest epoch that is lower or equal to the `epoch` arg
|
|
bestEpoch := abi.ChainEpoch(0)
|
|
bestPrice := Prices[bestEpoch]
|
|
for e, pl := range Prices {
|
|
// if `e` happened after `bestEpoch` and `e` is earlier or equal to the target `epoch`
|
|
if e > bestEpoch && e <= epoch {
|
|
bestEpoch = e
|
|
bestPrice = pl
|
|
}
|
|
}
|
|
if bestPrice == nil {
|
|
panic(fmt.Sprintf("bad setup: no gas prices available for epoch %d", epoch))
|
|
}
|
|
return bestPrice
|
|
}
|
|
|
|
type pricedSyscalls struct {
|
|
under vmr.Syscalls
|
|
pl Pricelist
|
|
chargeGas func(GasCharge)
|
|
}
|
|
|
|
// Verifies that a signature is valid for an address and plaintext.
|
|
func (ps pricedSyscalls) VerifySignature(signature crypto.Signature, signer address.Address, plaintext []byte) error {
|
|
c, err := ps.pl.OnVerifySignature(signature.Type, len(plaintext))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ps.chargeGas(c)
|
|
defer ps.chargeGas(gasOnActorExec)
|
|
|
|
return ps.under.VerifySignature(signature, signer, plaintext)
|
|
}
|
|
|
|
// Hashes input data using blake2b with 256 bit output.
|
|
func (ps pricedSyscalls) HashBlake2b(data []byte) [32]byte {
|
|
ps.chargeGas(ps.pl.OnHashing(len(data)))
|
|
defer ps.chargeGas(gasOnActorExec)
|
|
|
|
return ps.under.HashBlake2b(data)
|
|
}
|
|
|
|
// Computes an unsealed sector CID (CommD) from its constituent piece CIDs (CommPs) and sizes.
|
|
func (ps pricedSyscalls) ComputeUnsealedSectorCID(reg abi.RegisteredSealProof, pieces []abi.PieceInfo) (cid.Cid, error) {
|
|
ps.chargeGas(ps.pl.OnComputeUnsealedSectorCid(reg, pieces))
|
|
defer ps.chargeGas(gasOnActorExec)
|
|
|
|
return ps.under.ComputeUnsealedSectorCID(reg, pieces)
|
|
}
|
|
|
|
// Verifies a sector seal proof.
|
|
func (ps pricedSyscalls) VerifySeal(vi proof7.SealVerifyInfo) error {
|
|
ps.chargeGas(ps.pl.OnVerifySeal(vi))
|
|
defer ps.chargeGas(gasOnActorExec)
|
|
|
|
return ps.under.VerifySeal(vi)
|
|
}
|
|
|
|
// Verifies a proof of spacetime.
|
|
func (ps pricedSyscalls) VerifyPoSt(vi proof7.WindowPoStVerifyInfo) error {
|
|
ps.chargeGas(ps.pl.OnVerifyPost(vi))
|
|
defer ps.chargeGas(gasOnActorExec)
|
|
|
|
return ps.under.VerifyPoSt(vi)
|
|
}
|
|
|
|
// Verifies that two block headers provide proof of a consensus fault:
|
|
// - both headers mined by the same actor
|
|
// - headers are different
|
|
// - first header is of the same or lower epoch as the second
|
|
// - at least one of the headers appears in the current chain at or after epoch `earliest`
|
|
// - the headers provide evidence of a fault (see the spec for the different fault types).
|
|
// The parameters are all serialized block headers. The third "extra" parameter is consulted only for
|
|
// the "parent grinding fault", in which case it must be the sibling of h1 (same parent tipset) and one of the
|
|
// blocks in the parent of h2 (i.e. h2's grandparent).
|
|
// Returns nil and an error if the headers don't prove a fault.
|
|
func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte) (*vmr.ConsensusFault, error) {
|
|
ps.chargeGas(ps.pl.OnVerifyConsensusFault())
|
|
defer ps.chargeGas(gasOnActorExec)
|
|
|
|
return ps.under.VerifyConsensusFault(h1, h2, extra)
|
|
}
|
|
|
|
func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]proof7.SealVerifyInfo) (map[address.Address][]bool, error) {
|
|
count := int64(0)
|
|
for _, svis := range inp {
|
|
count += int64(len(svis))
|
|
}
|
|
|
|
gasChargeSum := newGasCharge("BatchVerifySeals", 0, 0)
|
|
gasChargeSum = gasChargeSum.WithExtra(count).WithVirtual(15075005*count+899741502, 0)
|
|
ps.chargeGas(gasChargeSum) // real gas charged by actors
|
|
defer ps.chargeGas(gasOnActorExec)
|
|
|
|
return ps.under.BatchVerifySeals(inp)
|
|
}
|
|
|
|
func (ps pricedSyscalls) VerifyAggregateSeals(aggregate proof7.AggregateSealVerifyProofAndInfos) error {
|
|
ps.chargeGas(ps.pl.OnVerifyAggregateSeals(aggregate))
|
|
defer ps.chargeGas(gasOnActorExec)
|
|
|
|
return ps.under.VerifyAggregateSeals(aggregate)
|
|
}
|
|
|
|
func (ps pricedSyscalls) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) error {
|
|
ps.chargeGas(ps.pl.OnVerifyReplicaUpdate(update))
|
|
defer ps.chargeGas(gasOnActorExec)
|
|
|
|
return ps.under.VerifyReplicaUpdate(update)
|
|
}
|