Merge remote-tracking branch 'origin/testnet/3' into feat/new-workers
This commit is contained in:
commit
e6aa01653a
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -2,3 +2,6 @@
|
||||
path = extern/filecoin-ffi
|
||||
url = https://github.com/filecoin-project/filecoin-ffi.git
|
||||
branch = master
|
||||
[submodule "extern/serialization-vectors"]
|
||||
path = extern/serialization-vectors
|
||||
url = https://github.com/filecoin-project/serialization-vectors
|
||||
|
@ -64,7 +64,7 @@ const MaxSealLookback = SealRandomnessLookbackLimit + 2000
|
||||
// Mining
|
||||
|
||||
// Epochs
|
||||
const EcRandomnessLookback = 300
|
||||
const EcRandomnessLookback = 1
|
||||
|
||||
// /////
|
||||
// Devnet settings
|
||||
|
@ -3,8 +3,8 @@ package gen
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"github.com/minio/blake2b-simd"
|
||||
"io/ioutil"
|
||||
"sync/atomic"
|
||||
|
||||
@ -276,8 +276,12 @@ func CarWalkFunc(nd format.Node) (out []*format.Link, err error) {
|
||||
func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m address.Address, round int64) (*types.EPostProof, *types.Ticket, error) {
|
||||
mc := &mca{w: cg.w, sm: cg.sm}
|
||||
|
||||
// TODO: REVIEW: Am I doing this correctly?
|
||||
ticketRand, err := mc.ChainGetRandomness(ctx, pts.Key(), crypto.DomainSeparationTag_TicketProduction, pts.Height(), m.Bytes())
|
||||
buf := new(bytes.Buffer)
|
||||
if err := m.MarshalCBOR(buf); err != nil {
|
||||
return nil, nil, xerrors.Errorf("failed to cbor marshal address: %w", err)
|
||||
}
|
||||
|
||||
ticketRand, err := mc.ChainGetRandomness(ctx, pts.Key(), crypto.DomainSeparationTag_TicketProduction, abi.ChainEpoch(round-build.EcRandomnessLookback), buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -549,7 +553,11 @@ type ProofInput struct {
|
||||
}
|
||||
|
||||
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner address.Address, epp ElectionPoStProver, a MiningCheckAPI) (*ProofInput, error) {
|
||||
epostRand, err := a.ChainGetRandomness(ctx, ts.Key(), crypto.DomainSeparationTag_ElectionPoStChallengeSeed, abi.ChainEpoch(round-build.EcRandomnessLookback), miner.Bytes())
|
||||
buf := new(bytes.Buffer)
|
||||
if err := miner.MarshalCBOR(buf); err != nil {
|
||||
return nil, xerrors.Errorf("failed to cbor marshal address: %w")
|
||||
}
|
||||
epostRand, err := a.ChainGetRandomness(ctx, ts.Key(), crypto.DomainSeparationTag_ElectionPoStChallengeSeed, abi.ChainEpoch(round-build.EcRandomnessLookback), buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("chain get randomness: %w", err)
|
||||
}
|
||||
@ -584,7 +592,7 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add
|
||||
})
|
||||
}
|
||||
|
||||
hvrf := sha256.Sum256(vrfout)
|
||||
hvrf := blake2b.Sum256(vrfout)
|
||||
candidates, err := epp.GenerateCandidates(ctx, sinfos, hvrf[:])
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to generate electionPoSt candidates: %w", err)
|
||||
|
@ -2,12 +2,14 @@ package state
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
address "github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
)
|
||||
|
||||
@ -227,3 +229,45 @@ func assertNotHas(t *testing.T, st *StateTree, addr address.Address) {
|
||||
t.Fatal("shouldnt have found actor", addr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateTreeConsistency(t *testing.T) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var addrs []address.Address
|
||||
for i := 100; i < 150; i++ {
|
||||
a, err := address.NewIDAddress(uint64(i))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addrs = append(addrs, a)
|
||||
}
|
||||
|
||||
randomCid, err := cid.Decode("bafy2bzacecu7n7wbtogznrtuuvf73dsz7wasgyneqasksdblxupnyovmtwxxu")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i, a := range addrs {
|
||||
st.SetActor(a, &types.Actor{
|
||||
Code: randomCid,
|
||||
Head: randomCid,
|
||||
Balance: types.NewInt(uint64(10000 + i)),
|
||||
Nonce: uint64(1000 - i),
|
||||
})
|
||||
}
|
||||
|
||||
root, err := st.Flush(context.TODO())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("root is: ", root)
|
||||
if root.String() != "bafy2bzacec6igwshty4qqexix6iffzdawp5e4ke7mamfn35g3ga6rc3dyhgnc" {
|
||||
t.Fatal("MISMATCH!")
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
package chain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/minio/blake2b-simd"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -617,7 +618,11 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
})
|
||||
|
||||
tktsCheck := async.Err(func() error {
|
||||
vrfBase, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs.Cids(), crypto.DomainSeparationTag_TicketProduction, int64(baseTs.Height()), h.Miner.Bytes())
|
||||
buf := new(bytes.Buffer)
|
||||
if err := h.Miner.MarshalCBOR(buf); err != nil {
|
||||
return xerrors.Errorf("failed to marshal miner address to cbor: %w", err)
|
||||
}
|
||||
vrfBase, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs.Cids(), crypto.DomainSeparationTag_TicketProduction, int64(baseTs.Height()), buf.Bytes())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get randomness for verifying election proof: %w", err)
|
||||
}
|
||||
@ -656,7 +661,11 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
}
|
||||
|
||||
func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.BlockHeader, baseTs *types.TipSet, waddr address.Address) error {
|
||||
rand, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs.Cids(), crypto.DomainSeparationTag_ElectionPoStChallengeSeed, int64(h.Height-build.EcRandomnessLookback), h.Miner.Bytes())
|
||||
buf := new(bytes.Buffer)
|
||||
if err := h.Miner.MarshalCBOR(buf); err != nil {
|
||||
return xerrors.Errorf("failed to marshal miner to cbor: %w", err)
|
||||
}
|
||||
rand, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs.Cids(), crypto.DomainSeparationTag_ElectionPoStChallengeSeed, int64(h.Height-build.EcRandomnessLookback), buf.Bytes())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get randomness for verifying election proof: %w", err)
|
||||
}
|
||||
@ -725,7 +734,7 @@ func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.Bloc
|
||||
// TODO: why do we need this here?
|
||||
challengeCount := sectorbuilder.ElectionPostChallengeCount(uint64(len(sectorInfo)), 0)
|
||||
|
||||
hvrf := sha256.Sum256(h.EPostProof.PostRand)
|
||||
hvrf := blake2b.Sum256(h.EPostProof.PostRand)
|
||||
pvi := abi.PoStVerifyInfo{
|
||||
Randomness: hvrf[:],
|
||||
Candidates: candidates,
|
||||
|
197
chain/vectors/gen/main.go
Normal file
197
chain/vectors/gen/main.go
Normal file
@ -0,0 +1,197 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
"github.com/filecoin-project/lotus/chain/vectors"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
)
|
||||
|
||||
func init() {
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
}
|
||||
|
||||
func MakeHeaderVectors() []vectors.HeaderVector {
|
||||
cg, err := gen.NewGenerator()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var out []vectors.HeaderVector
|
||||
for i := 0; i < 5; i++ {
|
||||
nts, err := cg.NextTipSet()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
h := nts.TipSet.Blocks[0].Header
|
||||
data, err := h.Serialize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
out = append(out, vectors.HeaderVector{
|
||||
Block: h,
|
||||
Cid: h.Cid().String(),
|
||||
CborHex: fmt.Sprintf("%x", data),
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func MakeMessageSigningVectors() []vectors.MessageSigningVector {
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
blsk, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bki, err := w.Export(blsk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
to, err := address.NewIDAddress(99999)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bmsg := mock.MkMessage(blsk, to, 55, w)
|
||||
|
||||
blsmsv := vectors.MessageSigningVector{
|
||||
Unsigned: &bmsg.Message,
|
||||
Cid: bmsg.Message.Cid().String(),
|
||||
CidHexBytes: fmt.Sprintf("%x", bmsg.Message.Cid().Bytes()),
|
||||
PrivateKey: bki.PrivateKey,
|
||||
Signature: &bmsg.Signature,
|
||||
}
|
||||
|
||||
secpk, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ski, err := w.Export(secpk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
smsg := mock.MkMessage(secpk, to, 55, w)
|
||||
|
||||
smsv := vectors.MessageSigningVector{
|
||||
Unsigned: &smsg.Message,
|
||||
Cid: smsg.Message.Cid().String(),
|
||||
CidHexBytes: fmt.Sprintf("%x", smsg.Message.Cid().Bytes()),
|
||||
PrivateKey: ski.PrivateKey,
|
||||
Signature: &smsg.Signature,
|
||||
}
|
||||
|
||||
return []vectors.MessageSigningVector{blsmsv, smsv}
|
||||
}
|
||||
|
||||
func MakeUnsignedMessageVectors() []vectors.UnsignedMessageVector {
|
||||
froms := []string{
|
||||
"t2ch7krq7l35i74rebqbjdsp3ucl47t24e3juxjfa",
|
||||
"t1pyfq7dg6sq65acyomqvzvbgwni4zllglqffw5dy",
|
||||
"t1cyg66djxytxhzdq7ynoqfxk7xinp6xsejbeufli",
|
||||
"t16n7vrq5humzoqll7zg4yw6dta645tuakcoalp6y",
|
||||
"t1awsiuji4wpbxpzslg36f3wnfxzi4o5gq67tz2mi",
|
||||
"t14mb3j32uuwajy5b2mliz63isp6zl5xkppzyuhfy",
|
||||
"t1dzdmyzzdy6q5elobj63eokzv2xnwsp4vm5l6aka",
|
||||
"t1svd45rkcfpsyqedvvhuv77yvllvu5ygmygjlvka",
|
||||
"t1mrret5liwh46qde6qhaxrmcwil7jawjeqdijwfq",
|
||||
"t1ly3ynedw74p4q3ytdnb4stjdkiodrl54moeyxea",
|
||||
"t1uqexvn66gj4lxkbvmrgposwrlxbyd655o2nayyi",
|
||||
"t1dwwjod7vw62jzw2eva7gtxohaidjhgh6w2rofui",
|
||||
"t1slswisymmkfulmvl3jynrnwqi27tkvmsgzhztvy",
|
||||
"t1e3vymxcdqfkqwz6e6wnxxx6ayuml3vxi5gef4xa",
|
||||
"t1bgqopgk64ywpprka4citgi62aldclyaegvwvx6y",
|
||||
"t1aizqgl2klzkzffwu35rufyuzefke2i6ndbewuhi",
|
||||
"t1mzposcnsd2tc66yu5i3kajtrh5pvwohdjvitcey",
|
||||
"t1x7xvs6oorrrlefyzn6wlbvaibzj3a2fyt4hsmvq",
|
||||
"t1ez743nvc4j7qfirwnmxbh4qdqwha3iyalnq4rya",
|
||||
"t17dvtgkop7cqgi6myjne5kzvrnsbg5wnowjphhwy",
|
||||
"t1kvar5z3q7dwrfxjqsnuqpq5qsd7mvh2xypblwta",
|
||||
}
|
||||
var out []vectors.UnsignedMessageVector
|
||||
for _, a := range froms {
|
||||
from, err := address.NewFromString(a)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
to, err := address.NewIDAddress(rand.Uint64())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
params := make([]byte, 32)
|
||||
rand.Read(params)
|
||||
|
||||
msg := &types.Message{
|
||||
To: to,
|
||||
From: from,
|
||||
Value: types.NewInt(rand.Uint64()),
|
||||
Method: abi.MethodNum(rand.Uint64()),
|
||||
GasPrice: types.NewInt(rand.Uint64()),
|
||||
GasLimit: rand.Int63(),
|
||||
Nonce: rand.Uint64(),
|
||||
Params: params,
|
||||
}
|
||||
|
||||
ser, err := msg.Serialize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
out = append(out, vectors.UnsignedMessageVector{
|
||||
Message: msg,
|
||||
HexCbor: fmt.Sprintf("%x", ser),
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func WriteJsonToFile(fname string, obj interface{}) error {
|
||||
fi, err := os.Create(fname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fi.Close()
|
||||
|
||||
out, err := json.MarshalIndent(obj, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fi.Write(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := WriteJsonToFile("block_headers.json", MakeHeaderVectors()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := WriteJsonToFile("message_signing.json", MakeMessageSigningVectors()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := WriteJsonToFile("unsigned_messages.json", MakeUnsignedMessageVectors()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
25
chain/vectors/vector_types.go
Normal file
25
chain/vectors/vector_types.go
Normal file
@ -0,0 +1,25 @@
|
||||
package vectors
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
)
|
||||
|
||||
type HeaderVector struct {
|
||||
Block *types.BlockHeader `json:"block"`
|
||||
CborHex string `json:"cbor_hex"`
|
||||
Cid string `json:"cid"`
|
||||
}
|
||||
|
||||
type MessageSigningVector struct {
|
||||
Unsigned *types.Message
|
||||
Cid string
|
||||
CidHexBytes string
|
||||
PrivateKey []byte
|
||||
Signature *crypto.Signature
|
||||
}
|
||||
|
||||
type UnsignedMessageVector struct {
|
||||
Message *types.Message `json:"message"`
|
||||
HexCbor string `json:"hex_cbor"`
|
||||
}
|
45
chain/vectors/vectors_test.go
Normal file
45
chain/vectors/vectors_test.go
Normal file
@ -0,0 +1,45 @@
|
||||
package vectors
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func LoadVector(t *testing.T, f string, out interface{}) {
|
||||
p := filepath.Join("../../extern/serialization-vectors", f)
|
||||
fi, err := os.Open(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(fi).Decode(out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockHeaderVectors(t *testing.T) {
|
||||
var headers []HeaderVector
|
||||
LoadVector(t, "block_headers.json", &headers)
|
||||
|
||||
for i, hv := range headers {
|
||||
if hv.Block.Cid().String() != hv.Cid {
|
||||
t.Fatalf("CID mismatch in test vector %d", i)
|
||||
}
|
||||
|
||||
data, err := hv.Block.Serialize()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if fmt.Sprintf("%x", data) != hv.CborHex {
|
||||
t.Fatalf("serialized data mismatched for test vector %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageSigningVectors(t *testing.T) {
|
||||
// TODO:
|
||||
}
|
141
chain/vm/gas.go
Normal file
141
chain/vm/gas.go
Normal file
@ -0,0 +1,141 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
addr "github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
vmr "github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
// Pricelist provides prices for operations in the VM.
|
||||
//
|
||||
// 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) int64
|
||||
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
||||
OnChainReturnValue(dataSize int) int64
|
||||
|
||||
// OnMethodInvocation returns the gas used when invoking a method.
|
||||
OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) int64
|
||||
|
||||
// OnIpldGet returns the gas used for storing an object
|
||||
OnIpldGet(dataSize int) int64
|
||||
// OnIpldPut returns the gas used for storing an object
|
||||
OnIpldPut(dataSize int) int64
|
||||
|
||||
// OnCreateActor returns the gas used for creating an actor
|
||||
OnCreateActor() int64
|
||||
// OnDeleteActor returns the gas used for deleting an actor
|
||||
OnDeleteActor() int64
|
||||
|
||||
OnVerifySignature(sigType crypto.SigType, planTextSize int) int64
|
||||
OnHashing(dataSize int) int64
|
||||
OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) int64
|
||||
OnVerifySeal(info abi.SealVerifyInfo) int64
|
||||
OnVerifyPost(info abi.PoStVerifyInfo) int64
|
||||
OnVerifyConsensusFault() int64
|
||||
}
|
||||
|
||||
var prices = map[abi.ChainEpoch]Pricelist{
|
||||
abi.ChainEpoch(0): &pricelistV0{
|
||||
onChainMessageBase: 0,
|
||||
onChainMessagePerByte: 2,
|
||||
onChainReturnValuePerByte: 8,
|
||||
sendBase: 5,
|
||||
sendTransferFunds: 5,
|
||||
sendInvokeMethod: 10,
|
||||
ipldGetBase: 10,
|
||||
ipldGetPerByte: 1,
|
||||
ipldPutBase: 20,
|
||||
ipldPutPerByte: 2,
|
||||
createActorBase: 40, // IPLD put + 20
|
||||
createActorExtra: 500,
|
||||
deleteActor: -500, // -createActorExtra
|
||||
// Dragons: this cost is not persistable, create a LinearCost{a,b} struct that has a `.Cost(x) -> ax + b`
|
||||
verifySignature: map[crypto.SigType]func(int64) int64{
|
||||
crypto.SigTypeBLS: func(x int64) int64 { return 3*x + 2 },
|
||||
crypto.SigTypeSecp256k1: func(x int64) int64 { return 3*x + 2 },
|
||||
},
|
||||
hashingBase: 5,
|
||||
hashingPerByte: 2,
|
||||
computeUnsealedSectorCidBase: 100,
|
||||
verifySealBase: 2000,
|
||||
verifyPostBase: 700,
|
||||
verifyConsensusFault: 10,
|
||||
},
|
||||
}
|
||||
|
||||
// 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(int64)
|
||||
}
|
||||
|
||||
// Verifies that a signature is valid for an address and plaintext.
|
||||
func (ps pricedSyscalls) VerifySignature(signature crypto.Signature, signer addr.Address, plaintext []byte) error {
|
||||
ps.chargeGas(ps.pl.OnVerifySignature(signature.Type, len(plaintext)))
|
||||
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)))
|
||||
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.RegisteredProof, pieces []abi.PieceInfo) (cid.Cid, error) {
|
||||
ps.chargeGas(ps.pl.OnComputeUnsealedSectorCid(reg, pieces))
|
||||
return ps.under.ComputeUnsealedSectorCID(reg, pieces)
|
||||
}
|
||||
|
||||
// Verifies a sector seal proof.
|
||||
func (ps pricedSyscalls) VerifySeal(vi abi.SealVerifyInfo) error {
|
||||
ps.chargeGas(ps.pl.OnVerifySeal(vi))
|
||||
return ps.under.VerifySeal(vi)
|
||||
}
|
||||
|
||||
// Verifies a proof of spacetime.
|
||||
func (ps pricedSyscalls) VerifyPoSt(vi abi.PoStVerifyInfo) error {
|
||||
ps.chargeGas(ps.pl.OnVerifyPost(vi))
|
||||
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, earliest abi.ChainEpoch) (*runtime.ConsensusFault, error) {
|
||||
ps.chargeGas(ps.pl.OnVerifyConsensusFault())
|
||||
return ps.under.VerifyConsensusFault(h1, h2, extra, earliest)
|
||||
}
|
165
chain/vm/gas_v0.go
Normal file
165
chain/vm/gas_v0.go
Normal file
@ -0,0 +1,165 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||
)
|
||||
|
||||
type pricelistV0 struct {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// System operations
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Gas cost charged to the originator of an on-chain message (regardless of
|
||||
// whether it succeeds or fails in application) is given by:
|
||||
// OnChainMessageBase + len(serialized message)*OnChainMessagePerByte
|
||||
// Together, these account for the cost of message propagation and validation,
|
||||
// up to but excluding any actual processing by the VM.
|
||||
// This is the cost a block producer burns when including an invalid message.
|
||||
onChainMessageBase int64
|
||||
onChainMessagePerByte int64
|
||||
|
||||
// Gas cost charged to the originator of a non-nil return value produced
|
||||
// by an on-chain message is given by:
|
||||
// len(return value)*OnChainReturnValuePerByte
|
||||
onChainReturnValuePerByte int64
|
||||
|
||||
// Gas cost for any message send execution(including the top-level one
|
||||
// initiated by an on-chain message).
|
||||
// This accounts for the cost of loading sender and receiver actors and
|
||||
// (for top-level messages) incrementing the sender's sequence number.
|
||||
// Load and store of actor sub-state is charged separately.
|
||||
sendBase int64
|
||||
|
||||
// Gas cost charged, in addition to SendBase, if a message send
|
||||
// is accompanied by any nonzero currency amount.
|
||||
// Accounts for writing receiver's new balance (the sender's state is
|
||||
// already accounted for).
|
||||
sendTransferFunds int64
|
||||
|
||||
// Gas cost charged, in addition to SendBase, if a message invokes
|
||||
// a method on the receiver.
|
||||
// Accounts for the cost of loading receiver code and method dispatch.
|
||||
sendInvokeMethod int64
|
||||
|
||||
// Gas cost (Base + len*PerByte) for any Get operation to the IPLD store
|
||||
// in the runtime VM context.
|
||||
ipldGetBase int64
|
||||
ipldGetPerByte int64
|
||||
|
||||
// Gas cost (Base + len*PerByte) for any Put operation to the IPLD store
|
||||
// in the runtime VM context.
|
||||
//
|
||||
// Note: these costs should be significantly higher than the costs for Get
|
||||
// operations, since they reflect not only serialization/deserialization
|
||||
// but also persistent storage of chain data.
|
||||
ipldPutBase int64
|
||||
ipldPutPerByte int64
|
||||
|
||||
// Gas cost for creating a new actor (via InitActor's Exec method).
|
||||
//
|
||||
// Note: this costs assume that the extra will be partially or totally refunded while
|
||||
// the base is covering for the put.
|
||||
createActorBase int64
|
||||
createActorExtra int64
|
||||
|
||||
// Gas cost for deleting an actor.
|
||||
//
|
||||
// Note: this partially refunds the create cost to incentivise the deletion of the actors.
|
||||
deleteActor int64
|
||||
|
||||
verifySignature map[crypto.SigType]func(len int64) int64
|
||||
|
||||
hashingBase int64
|
||||
hashingPerByte int64
|
||||
|
||||
computeUnsealedSectorCidBase int64
|
||||
verifySealBase int64
|
||||
verifyPostBase int64
|
||||
verifyConsensusFault int64
|
||||
}
|
||||
|
||||
var _ Pricelist = (*pricelistV0)(nil)
|
||||
|
||||
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
|
||||
func (pl *pricelistV0) OnChainMessage(msgSize int) int64 {
|
||||
return pl.onChainMessageBase + pl.onChainMessagePerByte*int64(msgSize)
|
||||
}
|
||||
|
||||
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
||||
func (pl *pricelistV0) OnChainReturnValue(dataSize int) int64 {
|
||||
return int64(dataSize) * pl.onChainReturnValuePerByte
|
||||
}
|
||||
|
||||
// OnMethodInvocation returns the gas used when invoking a method.
|
||||
func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) int64 {
|
||||
ret := pl.sendBase
|
||||
if value != abi.NewTokenAmount(0) {
|
||||
ret += pl.sendTransferFunds
|
||||
}
|
||||
if methodNum != builtin.MethodSend {
|
||||
ret += pl.sendInvokeMethod
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// OnIpldGet returns the gas used for storing an object
|
||||
func (pl *pricelistV0) OnIpldGet(dataSize int) int64 {
|
||||
return pl.ipldGetBase + int64(dataSize)*pl.ipldGetPerByte
|
||||
}
|
||||
|
||||
// OnIpldPut returns the gas used for storing an object
|
||||
func (pl *pricelistV0) OnIpldPut(dataSize int) int64 {
|
||||
return pl.ipldPutBase + int64(dataSize)*pl.ipldPutPerByte
|
||||
}
|
||||
|
||||
// OnCreateActor returns the gas used for creating an actor
|
||||
func (pl *pricelistV0) OnCreateActor() int64 {
|
||||
return pl.createActorBase + pl.createActorExtra
|
||||
}
|
||||
|
||||
// OnDeleteActor returns the gas used for deleting an actor
|
||||
func (pl *pricelistV0) OnDeleteActor() int64 {
|
||||
return pl.deleteActor
|
||||
}
|
||||
|
||||
// OnVerifySignature
|
||||
func (pl *pricelistV0) OnVerifySignature(sigType crypto.SigType, planTextSize int) int64 {
|
||||
costFn, ok := pl.verifySignature[sigType]
|
||||
if !ok {
|
||||
// TODO: fix retcode to be int64
|
||||
panic(aerrors.Newf(uint8(exitcode.SysErrInternal&0xff), "Cost function for signature type %d not supported", sigType))
|
||||
}
|
||||
return costFn(int64(planTextSize))
|
||||
}
|
||||
|
||||
// OnHashing
|
||||
func (pl *pricelistV0) OnHashing(dataSize int) int64 {
|
||||
return pl.hashingBase + int64(dataSize)*pl.hashingPerByte
|
||||
}
|
||||
|
||||
// OnComputeUnsealedSectorCid
|
||||
func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) int64 {
|
||||
// TODO: this needs more cost tunning, check with @lotus
|
||||
return pl.computeUnsealedSectorCidBase
|
||||
}
|
||||
|
||||
// OnVerifySeal
|
||||
func (pl *pricelistV0) OnVerifySeal(info abi.SealVerifyInfo) int64 {
|
||||
// TODO: this needs more cost tunning, check with @lotus
|
||||
return pl.verifySealBase
|
||||
}
|
||||
|
||||
// OnVerifyPost
|
||||
func (pl *pricelistV0) OnVerifyPost(info abi.PoStVerifyInfo) int64 {
|
||||
// TODO: this needs more cost tunning, check with @lotus
|
||||
return pl.verifyPostBase
|
||||
}
|
||||
|
||||
// OnVerifyConsensusFault
|
||||
func (pl *pricelistV0) OnVerifyConsensusFault() int64 {
|
||||
return pl.verifyConsensusFault
|
||||
}
|
@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
@ -28,11 +27,12 @@ import (
|
||||
type Runtime struct {
|
||||
ctx context.Context
|
||||
|
||||
vm *VM
|
||||
state *state.StateTree
|
||||
msg *types.Message
|
||||
height abi.ChainEpoch
|
||||
cst cbor.IpldStore
|
||||
vm *VM
|
||||
state *state.StateTree
|
||||
msg *types.Message
|
||||
height abi.ChainEpoch
|
||||
cst cbor.IpldStore
|
||||
pricelist Pricelist
|
||||
|
||||
gasAvailable int64
|
||||
gasUsed int64
|
||||
@ -44,8 +44,7 @@ type Runtime struct {
|
||||
originNonce uint64
|
||||
|
||||
internalExecutions []*ExecutionResult
|
||||
// the first internal call has a value of 1 for this field
|
||||
internalCallCounter int64
|
||||
numActorsCreated uint64
|
||||
}
|
||||
|
||||
func (rs *Runtime) ResolveAddress(address address.Address) (ret address.Address, ok bool) {
|
||||
@ -78,13 +77,11 @@ func (rs *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if ar, ok := r.(aerrors.ActorError); ok {
|
||||
log.Warn("VM.Call failure: ", ar)
|
||||
debug.PrintStack()
|
||||
log.Errorf("VM.Call failure: %+v", ar)
|
||||
aerr = ar
|
||||
return
|
||||
}
|
||||
debug.PrintStack()
|
||||
log.Errorf("ERROR")
|
||||
log.Errorf("spec actors failure: %s", r)
|
||||
aerr = aerrors.Newf(1, "spec actors failure: %s", r)
|
||||
}
|
||||
}()
|
||||
@ -168,7 +165,7 @@ func (rt *Runtime) NewActorAddress() address.Address {
|
||||
if err := binary.Write(&b, binary.BigEndian, rt.originNonce); err != nil {
|
||||
rt.Abortf(exitcode.ErrSerialization, "writing nonce address into a buffer: %v", err)
|
||||
}
|
||||
if err := binary.Write(&b, binary.BigEndian, rt.internalCallCounter); err != nil { // TODO: expose on vm
|
||||
if err := binary.Write(&b, binary.BigEndian, rt.numActorsCreated); err != nil { // TODO: expose on vm
|
||||
rt.Abortf(exitcode.ErrSerialization, "writing callSeqNum address into a buffer: %v", err)
|
||||
}
|
||||
addr, err := address.NewActorAddress(b.Bytes())
|
||||
@ -176,10 +173,12 @@ func (rt *Runtime) NewActorAddress() address.Address {
|
||||
rt.Abortf(exitcode.ErrSerialization, "create actor address: %v", err)
|
||||
}
|
||||
|
||||
rt.incrementNumActorsCreated()
|
||||
return addr
|
||||
}
|
||||
|
||||
func (rt *Runtime) CreateActor(codeId cid.Cid, address address.Address) {
|
||||
rt.ChargeGas(rt.Pricelist().OnCreateActor())
|
||||
var err error
|
||||
|
||||
err = rt.state.SetActor(address, &types.Actor{
|
||||
@ -194,6 +193,7 @@ func (rt *Runtime) CreateActor(codeId cid.Cid, address address.Address) {
|
||||
}
|
||||
|
||||
func (rt *Runtime) DeleteActor() {
|
||||
rt.ChargeGas(rt.Pricelist().OnDeleteActor())
|
||||
act, err := rt.state.GetActor(rt.Message().Receiver())
|
||||
if err != nil {
|
||||
rt.Abortf(exitcode.SysErrInternal, "failed to load actor in delete actor: %s", err)
|
||||
@ -314,6 +314,7 @@ func (rt *Runtime) internalSend(to address.Address, method abi.MethodNum, value
|
||||
return nil, aerrors.Fatalf("snapshot failed: %s", err)
|
||||
}
|
||||
defer st.ClearSnapshot()
|
||||
rt.ChargeGas(rt.Pricelist().OnMethodInvocation(value, method))
|
||||
|
||||
ret, errSend, subrt := rt.vm.send(ctx, msg, rt, 0)
|
||||
if errSend != nil {
|
||||
@ -339,7 +340,7 @@ func (rt *Runtime) internalSend(to address.Address, method abi.MethodNum, value
|
||||
|
||||
if subrt != nil {
|
||||
er.Subcalls = subrt.internalExecutions
|
||||
rt.internalCallCounter = subrt.internalCallCounter
|
||||
rt.numActorsCreated = subrt.numActorsCreated
|
||||
}
|
||||
rt.internalExecutions = append(rt.internalExecutions, &er)
|
||||
return ret, errSend
|
||||
@ -400,8 +401,6 @@ func (rt *Runtime) GetBalance(a address.Address) (types.BigInt, aerrors.ActorErr
|
||||
}
|
||||
|
||||
func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
||||
rt.ChargeGas(gasCommit)
|
||||
|
||||
// TODO: we can make this more efficient in the future...
|
||||
act, err := rt.state.GetActor(rt.Message().Receiver())
|
||||
if err != nil {
|
||||
@ -422,8 +421,24 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
||||
}
|
||||
|
||||
func (rt *Runtime) ChargeGas(toUse int64) {
|
||||
rt.gasUsed = rt.gasUsed + toUse
|
||||
if rt.gasUsed > rt.gasAvailable {
|
||||
rt.Abortf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable)
|
||||
err := rt.chargeGasSafe(toUse)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *Runtime) chargeGasSafe(toUse int64) aerrors.ActorError {
|
||||
rt.gasUsed += toUse
|
||||
if rt.gasUsed > rt.gasAvailable {
|
||||
return aerrors.Newf(uint8(exitcode.SysErrOutOfGas), "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rt *Runtime) Pricelist() Pricelist {
|
||||
return rt.pricelist
|
||||
}
|
||||
|
||||
func (rt *Runtime) incrementNumActorsCreated() {
|
||||
rt.numActorsCreated++
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
suites "github.com/filecoin-project/chain-validation/suites"
|
||||
@ -37,6 +38,9 @@ func init() {
|
||||
/* tests to skip go here */
|
||||
tipset.TestInternalMessageApplicationFailure,
|
||||
tipset.TestInvalidSenderAddress,
|
||||
tipset.TestBlockMessageDeduplication,
|
||||
tipset.TestMinerSubmitFallbackPoSt,
|
||||
tipset.TestMinerMissPoStChallengeWindow,
|
||||
}}
|
||||
}
|
||||
|
||||
@ -46,7 +50,9 @@ func TestChainValidationMessageSuite(t *testing.T) {
|
||||
if TestSuiteSkipper.Skip(testCase) {
|
||||
continue
|
||||
}
|
||||
testCase(t, f)
|
||||
t.Run(caseName(testCase), func(t *testing.T) {
|
||||
testCase(t, f)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,6 +62,14 @@ func TestChainValidationTipSetSuite(t *testing.T) {
|
||||
if TestSuiteSkipper.Skip(testCase) {
|
||||
continue
|
||||
}
|
||||
testCase(t, f)
|
||||
t.Run(caseName(testCase), func(t *testing.T) {
|
||||
testCase(t, f)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func caseName(testCase suites.TestCase) string {
|
||||
fqName := runtime.FuncForPC(reflect.ValueOf(testCase).Pointer()).Name()
|
||||
toks := strings.Split(fqName, ".")
|
||||
return toks[len(toks)-1]
|
||||
}
|
||||
|
@ -92,22 +92,22 @@ var _ cbor.IpldBlockstore = (*gasChargingBlocks)(nil)
|
||||
|
||||
type gasChargingBlocks struct {
|
||||
chargeGas func(int64)
|
||||
pricelist Pricelist
|
||||
under cbor.IpldBlockstore
|
||||
}
|
||||
|
||||
func (bs *gasChargingBlocks) Get(c cid.Cid) (block.Block, error) {
|
||||
bs.chargeGas(gasGetObj)
|
||||
blk, err := bs.under.Get(c)
|
||||
if err != nil {
|
||||
return nil, aerrors.Escalate(err, "failed to get block from blockstore")
|
||||
}
|
||||
bs.chargeGas(int64(len(blk.RawData())) * gasGetPerByte)
|
||||
bs.chargeGas(bs.pricelist.OnIpldGet(len(blk.RawData())))
|
||||
|
||||
return blk, nil
|
||||
}
|
||||
|
||||
func (bs *gasChargingBlocks) Put(blk block.Block) error {
|
||||
bs.chargeGas(gasPutObj + int64(len(blk.RawData()))*gasPutPerByte)
|
||||
bs.chargeGas(bs.pricelist.OnIpldPut(len(blk.RawData())))
|
||||
|
||||
if err := bs.under.Put(blk); err != nil {
|
||||
return aerrors.Escalate(err, "failed to write data to disk")
|
||||
@ -115,7 +115,7 @@ func (bs *gasChargingBlocks) Put(blk block.Block) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin address.Address, originNonce uint64, usedGas int64, icc int64) *Runtime {
|
||||
func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin address.Address, originNonce uint64, usedGas int64, nac uint64) *Runtime {
|
||||
rt := &Runtime{
|
||||
ctx: ctx,
|
||||
vm: vm,
|
||||
@ -124,16 +124,21 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres
|
||||
origin: origin,
|
||||
originNonce: originNonce,
|
||||
height: vm.blockHeight,
|
||||
sys: vm.Syscalls,
|
||||
|
||||
gasUsed: usedGas,
|
||||
gasAvailable: msg.GasLimit,
|
||||
internalCallCounter: icc,
|
||||
gasUsed: usedGas,
|
||||
gasAvailable: msg.GasLimit,
|
||||
numActorsCreated: nac,
|
||||
pricelist: PricelistByEpoch(vm.blockHeight),
|
||||
}
|
||||
rt.cst = &cbor.BasicIpldStore{
|
||||
Blocks: &gasChargingBlocks{rt.ChargeGas, vm.cst.Blocks},
|
||||
Blocks: &gasChargingBlocks{rt.ChargeGas, rt.pricelist, vm.cst.Blocks},
|
||||
Atlas: vm.cst.Atlas,
|
||||
}
|
||||
rt.sys = pricedSyscalls{
|
||||
under: vm.Syscalls,
|
||||
chargeGas: rt.ChargeGas,
|
||||
pl: rt.pricelist,
|
||||
}
|
||||
|
||||
return rt
|
||||
}
|
||||
@ -193,6 +198,8 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
||||
return nil, aerrors.Absorb(err, 1, "could not find source actor"), nil
|
||||
}
|
||||
|
||||
gasUsed := gasCharge
|
||||
|
||||
toActor, err := st.GetActor(msg.To)
|
||||
if err != nil {
|
||||
if xerrors.Is(err, init_.ErrAddressNotFound) {
|
||||
@ -201,31 +208,34 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
||||
return nil, aerrors.Absorb(err, 1, "could not create account"), nil
|
||||
}
|
||||
toActor = a
|
||||
gasUsed += PricelistByEpoch(vm.blockHeight).OnCreateActor()
|
||||
} else {
|
||||
return nil, aerrors.Escalate(err, "getting actor"), nil
|
||||
}
|
||||
}
|
||||
|
||||
gasUsed := gasCharge
|
||||
origin := msg.From
|
||||
on := msg.Nonce
|
||||
var icc int64 = 0
|
||||
var nac uint64 = 0
|
||||
if parent != nil {
|
||||
gasUsed = parent.gasUsed + gasUsed
|
||||
origin = parent.origin
|
||||
on = parent.originNonce
|
||||
icc = parent.internalCallCounter + 1
|
||||
nac = parent.numActorsCreated
|
||||
}
|
||||
rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, icc)
|
||||
rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac)
|
||||
if parent != nil {
|
||||
defer func() {
|
||||
parent.gasUsed = rt.gasUsed
|
||||
}()
|
||||
}
|
||||
|
||||
if types.BigCmp(msg.Value, types.NewInt(0)) != 0 {
|
||||
rt.ChargeGas(gasFundTransfer)
|
||||
aerr := rt.chargeGasSafe(rt.Pricelist().OnMethodInvocation(msg.Value, msg.Method))
|
||||
if aerr != nil {
|
||||
return nil, aerr, rt
|
||||
}
|
||||
|
||||
if types.BigCmp(msg.Value, types.NewInt(0)) != 0 {
|
||||
if err := Transfer(fromActor, toActor, msg.Value); err != nil {
|
||||
return nil, aerrors.Absorb(err, 1, "failed to transfer funds"), nil
|
||||
}
|
||||
@ -273,11 +283,13 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pl := PricelistByEpoch(vm.blockHeight)
|
||||
serMsg, err := msg.Serialize()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not serialize message: %w", err)
|
||||
}
|
||||
msgGasCost := int64(len(serMsg)) * gasPerMessageByte
|
||||
msgGasCost := pl.OnChainMessage(len(serMsg))
|
||||
// TODO: charge miner??
|
||||
if msgGasCost > msg.GasLimit {
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
@ -288,10 +300,6 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
|
||||
}
|
||||
|
||||
st := vm.cstate
|
||||
if err := st.Snapshot(ctx); err != nil {
|
||||
return nil, xerrors.Errorf("snapshot failed: %w", err)
|
||||
}
|
||||
defer st.ClearSnapshot()
|
||||
|
||||
fromActor, err := st.GetActor(msg.From)
|
||||
if err != nil {
|
||||
@ -310,7 +318,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
ExitCode: exitcode.SysErrInvalidCallSeqNum,
|
||||
GasUsed: msg.GasLimit,
|
||||
GasUsed: 0,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@ -333,8 +341,21 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
|
||||
|
||||
fromActor.Nonce++
|
||||
|
||||
if err := st.Snapshot(ctx); err != nil {
|
||||
return nil, xerrors.Errorf("snapshot failed: %w", err)
|
||||
}
|
||||
defer st.ClearSnapshot()
|
||||
|
||||
ret, actorErr, rt := vm.send(ctx, msg, nil, msgGasCost)
|
||||
|
||||
{
|
||||
actorErr2 := rt.chargeGasSafe(rt.Pricelist().OnChainReturnValue(len(ret)))
|
||||
if actorErr == nil {
|
||||
//TODO: Ambigous what to do in this case
|
||||
actorErr = actorErr2
|
||||
}
|
||||
}
|
||||
|
||||
if aerrors.IsFatal(actorErr) {
|
||||
return nil, xerrors.Errorf("[from=%s,to=%s,n=%d,m=%d,h=%d] fatal error: %w", msg.From, msg.To, msg.Nonce, msg.Method, vm.blockHeight, actorErr)
|
||||
}
|
||||
@ -353,6 +374,9 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
|
||||
}
|
||||
} else {
|
||||
gasUsed = rt.gasUsed
|
||||
if gasUsed < 0 {
|
||||
gasUsed = 0
|
||||
}
|
||||
// refund unused gas
|
||||
refund := types.BigMul(types.NewInt(uint64(msg.GasLimit-gasUsed)), msg.GasPrice)
|
||||
if err := Transfer(gasHolder, fromActor, refund); err != nil {
|
||||
@ -547,7 +571,6 @@ func (vm *VM) Invoke(act *types.Actor, rt *Runtime, method abi.MethodNum, params
|
||||
defer func() {
|
||||
rt.ctx = oldCtx
|
||||
}()
|
||||
rt.ChargeGas(gasInvoke)
|
||||
ret, err := vm.inv.Invoke(act, rt, method, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
1
extern/serialization-vectors
vendored
Submodule
1
extern/serialization-vectors
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 1e778d5bd77f758e83a18c41d10c2649b0e70fef
|
2
go.mod
2
go.mod
@ -12,7 +12,7 @@ require (
|
||||
github.com/coreos/go-systemd/v22 v22.0.0
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/elastic/go-sysinfo v1.3.0
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200318065243-0ccb5ec3afc5
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200320210432-2793319e9867
|
||||
github.com/filecoin-project/filecoin-ffi v0.0.0-20200304181354-4446ff8a1bb9
|
||||
github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be
|
||||
github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200131012142-05d80eeccc5e
|
||||
|
6
go.sum
6
go.sum
@ -102,8 +102,8 @@ github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7
|
||||
github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=
|
||||
github.com/fatih/color v1.8.0 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY=
|
||||
github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8=
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200318065243-0ccb5ec3afc5 h1:cr9+8iX+u9fDV53MWqqZw820EyeWVX+h/HCz56JUWb0=
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200318065243-0ccb5ec3afc5/go.mod h1:7HoEkq8OWN3vGcCZ4SRGxAPeL/mLckS+PNV3F0XmrCs=
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200320210432-2793319e9867 h1:6+9Khz+vidBfWG7xQ6a2uRpLnd3RhMVcOwJxu3XhvgI=
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200320210432-2793319e9867/go.mod h1:YTLxUr6gOZpkUaXzLe7OZ4s1dpfJGp2FY/J2/K5DJqc=
|
||||
github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5 h1:/MmWluswvDIbuPvBct4q6HeQgVm62O2DzWYTB38kt4A=
|
||||
github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0=
|
||||
github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be h1:TooKBwR/g8jG0hZ3lqe9S5sy2vTUcLOZLlz3M5wGn2E=
|
||||
@ -141,8 +141,6 @@ github.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.m
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200226200336-94c9b92b2775/go.mod h1:0HAWYrvajFHDgRaKbF0rl+IybVLZL5z4gQ8koCMPhoU=
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200302223606-0eaf97b10aaf/go.mod h1:0HAWYrvajFHDgRaKbF0rl+IybVLZL5z4gQ8koCMPhoU=
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200306000749-99e98e61e2a0/go.mod h1:0HAWYrvajFHDgRaKbF0rl+IybVLZL5z4gQ8koCMPhoU=
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200311215506-e95895452888 h1:VCrkpFmZuQRyHrUpFTS3K/09cCQDMi/ZJUQ6c4zr1g4=
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200311215506-e95895452888/go.mod h1:5WngRgTN5Eo4+0SjCBqLzEr2l6Mj45DrP2606gBhqI0=
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200312030511-3f5510bf6130 h1:atiWEDtI/gzSm89fL+NyneLN3eHfBd1QPgOZyXPjA5M=
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200312030511-3f5510bf6130/go.mod h1:5WngRgTN5Eo4+0SjCBqLzEr2l6Mj45DrP2606gBhqI0=
|
||||
github.com/filecoin-project/specs-storage v0.0.0-20200303233430-1a5a408f7513 h1:okBx3lPomwDxlPmRvyP078BwivDfdxNUlpCDhDD0ia8=
|
||||
|
@ -1,12 +1,13 @@
|
||||
package miner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
address "github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
@ -348,7 +349,12 @@ func (m *Miner) computeTicket(ctx context.Context, addr address.Address, base *M
|
||||
return nil, err
|
||||
}
|
||||
|
||||
input, err := m.api.ChainGetRandomness(ctx, base.ts.Key(), crypto.DomainSeparationTag_TicketProduction, base.ts.Height(), addr.Bytes())
|
||||
buf := new(bytes.Buffer)
|
||||
if err := addr.MarshalCBOR(buf); err != nil {
|
||||
return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err)
|
||||
}
|
||||
|
||||
input, err := m.api.ChainGetRandomness(ctx, base.ts.Key(), crypto.DomainSeparationTag_TicketProduction, base.ts.Height(), buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user