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"
|
|
addr "github.com/filecoin-project/go-address"
|
|
"github.com/filecoin-project/go-state-types/abi"
|
|
"github.com/filecoin-project/go-state-types/crypto"
|
|
"github.com/filecoin-project/lotus/build"
|
|
vmr "github.com/filecoin-project/specs-actors/v7/actors/runtime"
|
|
proof7 "github.com/filecoin-project/specs-actors/v7/actors/runtime/proof"
|
|
)
|
|
|
|
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,
|
|
},
|
|
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
|
|
|
|
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,
|
|
},
|
|
build.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 addr.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)
|
|
}
|