Merge pull request #1450 from filecoin-project/asr/gas

Re: #1446: Enable gas tracking in validation tests
This commit is contained in:
Whyrusleeping 2020-03-25 12:53:57 -07:00 committed by GitHub
commit 1aef03bdd7
21 changed files with 194 additions and 200 deletions

View File

@ -9,7 +9,6 @@ import (
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
) )
@ -343,6 +342,6 @@ func (e *calledEvents) Called(check CheckFunc, hnd CalledHandler, rev RevertHand
return nil return nil
} }
func (e *calledEvents) CalledMsg(ctx context.Context, hnd CalledHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, msg store.ChainMsg) error { func (e *calledEvents) CalledMsg(ctx context.Context, hnd CalledHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, msg types.ChainMsg) error {
return e.Called(e.CheckMsg(ctx, msg, hnd), hnd, rev, confidence, timeout, e.MatchMsg(msg.VMMessage())) return e.Called(e.CheckMsg(ctx, msg, hnd), hnd, rev, confidence, timeout, e.MatchMsg(msg.VMMessage()))
} }

View File

@ -5,11 +5,10 @@ import (
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
) )
func (e *calledEvents) CheckMsg(ctx context.Context, smsg store.ChainMsg, hnd CalledHandler) CheckFunc { func (e *calledEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd CalledHandler) CheckFunc {
msg := smsg.VMMessage() msg := smsg.VMMessage()
return func(ts *types.TipSet) (done bool, more bool, err error) { return func(ts *types.TipSet) (done bool, more bool, err error) {

View File

@ -31,7 +31,7 @@ func doExecValue(ctx context.Context, vm *vm.VM, to, from address.Address, value
return nil, xerrors.Errorf("doExec failed to get from actor: %w", err) return nil, xerrors.Errorf("doExec failed to get from actor: %w", err)
} }
ret, err := vm.ApplyMessage(ctx, &types.Message{ ret, err := vm.ApplyImplicitMessage(ctx, &types.Message{
To: to, To: to,
From: from, From: from,
Method: method, Method: method,

View File

@ -25,7 +25,6 @@ import (
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/modules/dtypes"
@ -109,11 +108,11 @@ func (ms *msgSet) add(m *types.SignedMessage) error {
type Provider interface { type Provider interface {
SubscribeHeadChanges(func(rev, app []*types.TipSet) error) *types.TipSet SubscribeHeadChanges(func(rev, app []*types.TipSet) error) *types.TipSet
PutMessage(m store.ChainMsg) (cid.Cid, error) PutMessage(m types.ChainMsg) (cid.Cid, error)
PubSubPublish(string, []byte) error PubSubPublish(string, []byte) error
StateGetActor(address.Address, *types.TipSet) (*types.Actor, error) StateGetActor(address.Address, *types.TipSet) (*types.Actor, error)
MessagesForBlock(*types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) MessagesForBlock(*types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error)
MessagesForTipset(*types.TipSet) ([]store.ChainMsg, error) MessagesForTipset(*types.TipSet) ([]types.ChainMsg, error)
LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error)
} }
@ -131,7 +130,7 @@ func (mpp *mpoolProvider) SubscribeHeadChanges(cb func(rev, app []*types.TipSet)
return mpp.sm.ChainStore().GetHeaviestTipSet() return mpp.sm.ChainStore().GetHeaviestTipSet()
} }
func (mpp *mpoolProvider) PutMessage(m store.ChainMsg) (cid.Cid, error) { func (mpp *mpoolProvider) PutMessage(m types.ChainMsg) (cid.Cid, error) {
return mpp.sm.ChainStore().PutMessage(m) return mpp.sm.ChainStore().PutMessage(m)
} }
@ -147,7 +146,7 @@ func (mpp *mpoolProvider) MessagesForBlock(h *types.BlockHeader) ([]*types.Messa
return mpp.sm.ChainStore().MessagesForBlock(h) return mpp.sm.ChainStore().MessagesForBlock(h)
} }
func (mpp *mpoolProvider) MessagesForTipset(ts *types.TipSet) ([]store.ChainMsg, error) { func (mpp *mpoolProvider) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) {
return mpp.sm.ChainStore().MessagesForTipset(ts) return mpp.sm.ChainStore().MessagesForTipset(ts)
} }

View File

@ -5,7 +5,6 @@ import (
"testing" "testing"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/mock" "github.com/filecoin-project/lotus/chain/types/mock"
"github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/chain/wallet"
@ -60,7 +59,7 @@ func (tma *testMpoolApi) SubscribeHeadChanges(cb func(rev, app []*types.TipSet)
return nil return nil
} }
func (tma *testMpoolApi) PutMessage(m store.ChainMsg) (cid.Cid, error) { func (tma *testMpoolApi) PutMessage(m types.ChainMsg) (cid.Cid, error) {
return cid.Undef, nil return cid.Undef, nil
} }
@ -79,7 +78,7 @@ func (tma *testMpoolApi) MessagesForBlock(h *types.BlockHeader) ([]*types.Messag
return nil, tma.bmsgs[h.Cid()], nil return nil, tma.bmsgs[h.Cid()], nil
} }
func (tma *testMpoolApi) MessagesForTipset(ts *types.TipSet) ([]store.ChainMsg, error) { func (tma *testMpoolApi) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) {
if len(ts.Blocks()) != 1 { if len(ts.Blocks()) != 1 {
panic("cant deal with multiblock tipsets in this test") panic("cant deal with multiblock tipsets in this test")
} }
@ -89,7 +88,7 @@ func (tma *testMpoolApi) MessagesForTipset(ts *types.TipSet) ([]store.ChainMsg,
return nil, err return nil, err
} }
var out []store.ChainMsg var out []types.ChainMsg
for _, m := range bm { for _, m := range bm {
out = append(out, m) out = append(out, m)
} }

View File

@ -188,7 +188,7 @@ func (st *StateTree) ClearSnapshot() {
st.snapshots = st.snapshots[:len(st.snapshots)-1] st.snapshots = st.snapshots[:len(st.snapshots)-1]
} }
func (st *StateTree) RegisterNewAddress(addr address.Address, act *types.Actor) (address.Address, error) { func (st *StateTree) RegisterNewAddress(addr address.Address) (address.Address, error) {
var out address.Address var out address.Address
err := st.MutateActor(builtin.InitActorAddr, func(initact *types.Actor) error { err := st.MutateActor(builtin.InitActorAddr, func(initact *types.Actor) error {
var ias init_.State var ias init_.State
@ -214,10 +214,6 @@ func (st *StateTree) RegisterNewAddress(addr address.Address, act *types.Actor)
return address.Undef, err return address.Undef, err
} }
if err := st.SetActor(out, act); err != nil {
return address.Undef, err
}
return out, nil return out, nil
} }

View File

@ -52,7 +52,7 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
msg.Nonce = fromActor.Nonce msg.Nonce = fromActor.Nonce
// TODO: maybe just use the invoker directly? // TODO: maybe just use the invoker directly?
ret, err := vmi.ApplyMessage(ctx, msg) ret, err := vmi.ApplyImplicitMessage(ctx, msg)
if err != nil { if err != nil {
return nil, xerrors.Errorf("apply message failed: %w", err) return nil, xerrors.Errorf("apply message failed: %w", err)
} }

View File

@ -140,8 +140,8 @@ func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (c
type BlockMessages struct { type BlockMessages struct {
Miner address.Address Miner address.Address
BlsMessages []store.ChainMsg BlsMessages []types.ChainMsg
SecpkMessages []store.ChainMsg SecpkMessages []types.ChainMsg
TicketCount int64 TicketCount int64
} }
@ -153,23 +153,8 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
return cid.Undef, cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err) return cid.Undef, cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err)
} }
applied := make(map[address.Address]uint64)
balances := make(map[address.Address]types.BigInt)
preloadAddr := func(a address.Address) error {
if _, ok := applied[a]; !ok {
act, err := vmi.StateTree().GetActor(a)
if err != nil {
return err
}
applied[a] = act.Nonce
balances[a] = act.Balance
}
return nil
}
var receipts []cbg.CBORMarshaler var receipts []cbg.CBORMarshaler
processedMsgs := map[cid.Cid]bool{}
for _, b := range bms { for _, b := range bms {
vmi.SetBlockMiner(b.Miner) vmi.SetBlockMiner(b.Miner)
@ -178,33 +163,24 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
for _, cm := range append(b.BlsMessages, b.SecpkMessages...) { for _, cm := range append(b.BlsMessages, b.SecpkMessages...) {
m := cm.VMMessage() m := cm.VMMessage()
if err := preloadAddr(m.From); err != nil { if _, found := processedMsgs[m.Cid()]; found {
return cid.Undef, cid.Undef, err
}
if applied[m.From] != m.Nonce {
continue continue
} }
applied[m.From]++ r, err := vmi.ApplyMessage(ctx, cm)
if balances[m.From].LessThan(m.RequiredFunds()) {
continue
}
balances[m.From] = types.BigSub(balances[m.From], m.RequiredFunds())
r, err := vmi.ApplyMessage(ctx, m)
if err != nil { if err != nil {
return cid.Undef, cid.Undef, err return cid.Undef, cid.Undef, err
} }
receipts = append(receipts, &r.MessageReceipt) receipts = append(receipts, &r.MessageReceipt)
gasReward = big.Add(gasReward, big.NewInt(r.GasUsed)) gasReward = big.Add(gasReward, big.NewInt(r.GasUsed))
penalty = big.Add(penalty, r.Penalty)
if cb != nil { if cb != nil {
if err := cb(cm.Cid(), m, r); err != nil { if err := cb(cm.Cid(), m, r); err != nil {
return cid.Undef, cid.Undef, err return cid.Undef, cid.Undef, err
} }
} }
processedMsgs[m.Cid()] = true
} }
var err error var err error
@ -233,7 +209,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
Method: builtin.MethodsReward.AwardBlockReward, Method: builtin.MethodsReward.AwardBlockReward,
Params: params, Params: params,
} }
ret, err := vmi.ApplyMessage(ctx, rwMsg) ret, err := vmi.ApplyImplicitMessage(ctx, rwMsg)
if err != nil { if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, err) return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, err)
} }
@ -265,7 +241,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
Method: builtin.MethodsCron.EpochTick, Method: builtin.MethodsCron.EpochTick,
Params: nil, Params: nil,
} }
ret, err := vmi.ApplyMessage(ctx, cronMsg) ret, err := vmi.ApplyImplicitMessage(ctx, cronMsg)
if err != nil { if err != nil {
return cid.Undef, cid.Undef, err return cid.Undef, cid.Undef, err
} }
@ -335,8 +311,8 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
bm := BlockMessages{ bm := BlockMessages{
Miner: b.Miner, Miner: b.Miner,
BlsMessages: make([]store.ChainMsg, 0, len(bms)), BlsMessages: make([]types.ChainMsg, 0, len(bms)),
SecpkMessages: make([]store.ChainMsg, 0, len(sms)), SecpkMessages: make([]types.ChainMsg, 0, len(sms)),
TicketCount: int64(len(b.EPostProof.Proofs)), TicketCount: int64(len(b.EPostProof.Proofs)),
} }
@ -615,7 +591,7 @@ func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid) (*ty
return fts, r, nil return fts, r, nil
} }
func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m store.ChainMsg) (*types.TipSet, *types.MessageReceipt, error) { func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg) (*types.TipSet, *types.MessageReceipt, error) {
cur := from cur := from
for { for {

View File

@ -330,6 +330,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
} }
for i, msg := range msgs { for i, msg := range msgs {
// TODO: Use the signed message length for secp messages
ret, err := vmi.ApplyMessage(ctx, msg) ret, err := vmi.ApplyMessage(ctx, msg)
if err != nil { if err != nil {
return cid.Undef, nil, xerrors.Errorf("applying message %s: %w", msg.Cid(), err) return cid.Undef, nil, xerrors.Errorf("applying message %s: %w", msg.Cid(), err)

View File

@ -597,7 +597,7 @@ func (cs *ChainStore) GetGenesis() (*types.BlockHeader, error) {
return types.DecodeBlock(genb.RawData()) return types.DecodeBlock(genb.RawData())
} }
func (cs *ChainStore) GetCMessage(c cid.Cid) (ChainMsg, error) { func (cs *ChainStore) GetCMessage(c cid.Cid) (types.ChainMsg, error) {
m, err := cs.GetMessage(c) m, err := cs.GetMessage(c)
if err == nil { if err == nil {
return m, nil return m, nil
@ -650,13 +650,7 @@ func (cs *ChainStore) readAMTCids(root cid.Cid) ([]cid.Cid, error) {
return cids, nil return cids, nil
} }
type ChainMsg interface { func (cs *ChainStore) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) {
Cid() cid.Cid
VMMessage() *types.Message
ToStorageBlock() (block.Block, error)
}
func (cs *ChainStore) MessagesForTipset(ts *types.TipSet) ([]ChainMsg, error) {
applied := make(map[address.Address]uint64) applied := make(map[address.Address]uint64)
balances := make(map[address.Address]types.BigInt) balances := make(map[address.Address]types.BigInt)
@ -679,14 +673,14 @@ func (cs *ChainStore) MessagesForTipset(ts *types.TipSet) ([]ChainMsg, error) {
return nil return nil
} }
var out []ChainMsg var out []types.ChainMsg
for _, b := range ts.Blocks() { for _, b := range ts.Blocks() {
bms, sms, err := cs.MessagesForBlock(b) bms, sms, err := cs.MessagesForBlock(b)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to get messages for block: %w", err) return nil, xerrors.Errorf("failed to get messages for block: %w", err)
} }
cmsgs := make([]ChainMsg, 0, len(bms)+len(sms)) cmsgs := make([]types.ChainMsg, 0, len(bms)+len(sms))
for _, m := range bms { for _, m := range bms {
cmsgs = append(cmsgs, m) cmsgs = append(cmsgs, m)
} }

View File

@ -95,6 +95,7 @@ func (cs *ChainStore) call(ctx context.Context, msg *types.Message, ts *types.Ti
msg.Nonce = fromActor.Nonce msg.Nonce = fromActor.Nonce
// TODO: maybe just use the invoker directly? // TODO: maybe just use the invoker directly?
// TODO: use signed message length for secp messages
ret, err := vmi.ApplyMessage(ctx, msg) ret, err := vmi.ApplyMessage(ctx, msg)
if err != nil { if err != nil {
return nil, xerrors.Errorf("apply message failed: %w", err) return nil, xerrors.Errorf("apply message failed: %w", err)

View File

@ -12,6 +12,13 @@ import (
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
) )
type ChainMsg interface {
Cid() cid.Cid
VMMessage() *Message
ToStorageBlock() (block.Block, error)
ChainLength() int
}
type Message struct { type Message struct {
To address.Address To address.Address
From address.Address From address.Address
@ -60,6 +67,14 @@ func (m *Message) Serialize() ([]byte, error) {
return buf.Bytes(), nil return buf.Bytes(), nil
} }
func (m *Message) ChainLength() int {
ser, err := m.Serialize()
if err != nil {
panic(err)
}
return len(ser)
}
func (m *Message) ToStorageBlock() (block.Block, error) { func (m *Message) ToStorageBlock() (block.Block, error) {
data, err := m.Serialize() data, err := m.Serialize()
if err != nil { if err != nil {

View File

@ -63,6 +63,14 @@ func (sm *SignedMessage) Serialize() ([]byte, error) {
return buf.Bytes(), nil return buf.Bytes(), nil
} }
func (m *SignedMessage) ChainLength() int {
ser, err := m.Serialize()
if err != nil {
panic(err)
}
return len(ser)
}
func (sm *SignedMessage) Size() int { func (sm *SignedMessage) Size() int {
serdata, err := sm.Serialize() serdata, err := sm.Serialize()
if err != nil { if err != nil {

View File

@ -41,7 +41,8 @@ func (a *Applier) ApplyMessage(eCtx *vtypes.ExecutionContext, state vstate.VMWra
return vtypes.MessageReceipt{}, err return vtypes.MessageReceipt{}, err
} }
ret, err := lotusVM.ApplyMessage(ctx, toLotusMsg(message)) lm := toLotusMsg(message)
ret, err := lotusVM.ApplyMessage(ctx, lm)
if err != nil { if err != nil {
return vtypes.MessageReceipt{}, err return vtypes.MessageReceipt{}, err
} }
@ -82,7 +83,7 @@ func (a *Applier) ApplyTipSetMessages(state vstate.VMWrapper, blocks []vtypes.Bl
} }
for _, m := range b.SECPMessages { for _, m := range b.SECPMessages {
bm.SecpkMessages = append(bm.SecpkMessages, toLotusMsg(&m.Message)) bm.SecpkMessages = append(bm.SecpkMessages, toLotusSignedMsg(m))
} }
bms = append(bms, bm) bms = append(bms, bm)
@ -145,3 +146,10 @@ func toLotusMsg(msg *vtypes.Message) *types.Message {
Params: msg.Params, Params: msg.Params,
} }
} }
func toLotusSignedMsg(msg *vtypes.SignedMessage) *types.SignedMessage {
return &types.SignedMessage{
Message: *toLotusMsg(&msg.Message),
Signature: msg.Signature,
}
}

View File

@ -39,7 +39,7 @@ func (f *Factories) NewRandomnessSource() vstate.RandomnessSource {
} }
func (f *Factories) NewValidationConfig() vstate.ValidationConfig { func (f *Factories) NewValidationConfig() vstate.ValidationConfig {
trackGas := false trackGas := true
checkExit := true checkExit := true
checkRet := true checkRet := true
// ignore gas and return value assertions // ignore gas and return value assertions

View File

@ -87,7 +87,8 @@ func (k *KeyManager) newBLSKey() *wallet.Key {
//sk := ffi.PrivateKeyGenerate(s.blsSeed) //sk := ffi.PrivateKeyGenerate(s.blsSeed)
// s.blsSeed++ // s.blsSeed++
sk := [32]byte{} sk := [32]byte{}
sk[0] = uint8(k.blsSeed + 1) // hack to keep gas values determinist sk[0] = uint8(k.blsSeed) // hack to keep gas values determinist
k.blsSeed++
key, err := wallet.NewKey(types.KeyInfo{ key, err := wallet.NewKey(types.KeyInfo{
Type: wallet.KTBLS, Type: wallet.KTBLS,
PrivateKey: sk[:], PrivateKey: sk[:],

View File

@ -4,7 +4,6 @@ import (
"context" "context"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore"
blockstore "github.com/ipfs/go-ipfs-blockstore" blockstore "github.com/ipfs/go-ipfs-blockstore"
@ -18,7 +17,6 @@ import (
vstate "github.com/filecoin-project/chain-validation/state" vstate "github.com/filecoin-project/chain-validation/state"
"github.com/filecoin-project/lotus/chain/gen/genesis"
"github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
) )
@ -116,37 +114,50 @@ func (s *StateWrapper) SetActorState(addr address.Address, balance abi.TokenAmou
} }
func (s *StateWrapper) CreateActor(code cid.Cid, addr address.Address, balance abi.TokenAmount, actorState runtime.CBORMarshaler) (vstate.Actor, address.Address, error) { func (s *StateWrapper) CreateActor(code cid.Cid, addr address.Address, balance abi.TokenAmount, actorState runtime.CBORMarshaler) (vstate.Actor, address.Address, error) {
if addr == builtin.InitActorAddr || addr == builtin.StoragePowerActorAddr || addr == builtin.StorageMarketActorAddr { idAddr := addr
act, err := s.SetupSingletonActor(addr) tree, err := state.LoadStateTree(s.cst, s.stateRoot)
if err != nil {
return nil, address.Undef, err
}
if addr.Protocol() != address.ID {
actHead, err := tree.Store.Put(context.Background(), actorState)
if err != nil { if err != nil {
return nil, address.Undef, err return nil, address.Undef, err
} }
return act, addr, nil actr := &actorWrapper{types.Actor{
Code: code,
Head: actHead,
Balance: balance,
}}
idAddr, err = tree.RegisterNewAddress(addr)
if err != nil {
return nil, address.Undef, xerrors.Errorf("register new address for actor: %w", err)
}
if err := tree.SetActor(addr, &actr.Actor); err != nil {
return nil, address.Undef, xerrors.Errorf("setting new actor for actor: %w", err)
}
} }
tree, err := state.LoadStateTree(s.cst, s.Root())
// store newState
head, err := tree.Store.Put(context.Background(), actorState)
if err != nil { if err != nil {
return nil, address.Undef, err return nil, address.Undef, err
} }
actHead, err := tree.Store.Put(context.Background(), actorState)
if err != nil { // create and store actor object
return nil, address.Undef, err a := types.Actor{
}
actr := &actorWrapper{types.Actor{
Code: code, Code: code,
Head: actHead, Head: head,
Balance: balance, Balance: balance,
}} }
if err := tree.SetActor(idAddr, &a); err != nil {
idAddr, err := tree.RegisterNewAddress(addr, &actr.Actor) return nil, address.Undef, err
if err != nil {
return nil, address.Undef, xerrors.Errorf("register new address for actor: %w", err)
} }
if err := tree.SetActor(addr, &actr.Actor); err != nil { return &actorWrapper{a}, idAddr, s.flush(tree)
return nil, address.Undef, xerrors.Errorf("setting new actor for actor: %w", err)
}
return actr, idAddr, s.flush(tree)
} }
// Flushes a state tree to storage and sets this state's root to that tree's root CID. // Flushes a state tree to storage and sets this state's root to that tree's root CID.
@ -192,46 +203,3 @@ type contextStore struct {
func (s *contextStore) Context() context.Context { func (s *contextStore) Context() context.Context {
return s.ctx return s.ctx
} }
func (s *StateWrapper) SetupSingletonActor(addr address.Address) (vstate.Actor, error) {
tree, err := state.LoadStateTree(s.cst, s.stateRoot)
if err != nil {
return nil, err
}
switch addr {
case builtin.InitActorAddr:
// FIXME this is going to be a problem if go-filecoin and lotus setup their init actors with different netnames
// ideally lotus should use the init actor constructor
initact, err := genesis.SetupInitActor(s.bs, "chain-validation", nil)
if err != nil {
return nil, xerrors.Errorf("setup init actor: %w", err)
}
if err := tree.SetActor(builtin.InitActorAddr, initact); err != nil {
return nil, xerrors.Errorf("set init actor: %w", err)
}
return &actorWrapper{*initact}, s.flush(tree)
case builtin.StorageMarketActorAddr:
smact, err := genesis.SetupStorageMarketActor(s.bs)
if err != nil {
return nil, xerrors.Errorf("setup storage marker actor: %w", err)
}
if err := tree.SetActor(builtin.StorageMarketActorAddr, smact); err != nil {
return nil, xerrors.Errorf("set storage marker actor: %w", err)
}
return &actorWrapper{*smact}, s.flush(tree)
case builtin.StoragePowerActorAddr:
spact, err := genesis.SetupStoragePowerActor(s.bs)
if err != nil {
return nil, xerrors.Errorf("setup storage power actor: %w", err)
}
if err := tree.SetActor(builtin.StoragePowerActorAddr, spact); err != nil {
return nil, xerrors.Errorf("set storage power actor: %w", err)
}
return &actorWrapper{*spact}, s.flush(tree)
default:
return nil, xerrors.Errorf("%v is not a singleton actor address", addr)
}
}

View File

@ -2,9 +2,11 @@ package vm
import ( import (
"context" "context"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/account"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
@ -27,25 +29,50 @@ func init() {
var EmptyObjectCid cid.Cid var EmptyObjectCid cid.Cid
// Creates account actors from only BLS/SECP256K1 addresses. // Creates account actors from only BLS/SECP256K1 addresses.
func TryCreateAccountActor(st *state.StateTree, addr address.Address) (*types.Actor, aerrors.ActorError) { func TryCreateAccountActor(ctx context.Context, rt *Runtime, addr address.Address) (*types.Actor, aerrors.ActorError) {
act, err := makeActor(st, addr) addrID, err := rt.state.RegisterNewAddress(addr)
if err != nil { if err != nil {
return nil, err
}
if _, err := st.RegisterNewAddress(addr, act); err != nil {
return nil, aerrors.Escalate(err, "registering actor address") return nil, aerrors.Escalate(err, "registering actor address")
} }
if err := rt.chargeGasSafe(PricelistByEpoch(rt.height).OnCreateActor()); err != nil {
return nil, err
}
act, aerr := makeActor(rt.state, addr)
if aerr != nil {
return nil, aerr
}
if err := rt.state.SetActor(addrID, act); err != nil {
return nil, aerrors.Escalate(err, "creating new actor failed")
}
p, err := actors.SerializeParams(&addr)
if err != nil {
return nil, aerrors.Escalate(err, "registering actor address")
}
// call constructor on account
_, aerr = rt.internalSend(builtin.SystemActorAddr, addrID, builtin.MethodsAccount.Constructor, big.Zero(), p)
if aerr != nil {
return nil, aerrors.Fatal("failed to invoke account constructor")
}
act, err = rt.state.GetActor(addrID)
if err != nil {
return nil, aerrors.Escalate(err, "loading newly created actor failed")
}
return act, nil return act, nil
} }
func makeActor(st *state.StateTree, addr address.Address) (*types.Actor, aerrors.ActorError) { func makeActor(st *state.StateTree, addr address.Address) (*types.Actor, aerrors.ActorError) {
switch addr.Protocol() { switch addr.Protocol() {
case address.BLS: case address.BLS:
return NewBLSAccountActor(st, addr) return NewBLSAccountActor()
case address.SECP256K1: case address.SECP256K1:
return NewSecp256k1AccountActor(st, addr) return NewSecp256k1AccountActor()
case address.ID: case address.ID:
return nil, aerrors.Newf(1, "no actor with given ID: %s", addr) return nil, aerrors.Newf(1, "no actor with given ID: %s", addr)
case address.Actor: case address.Actor:
@ -55,37 +82,21 @@ func makeActor(st *state.StateTree, addr address.Address) (*types.Actor, aerrors
} }
} }
func NewBLSAccountActor(st *state.StateTree, addr address.Address) (*types.Actor, aerrors.ActorError) { func NewBLSAccountActor() (*types.Actor, aerrors.ActorError) {
var acstate account.State
acstate.Address = addr
c, err := st.Store.Put(context.TODO(), &acstate)
if err != nil {
return nil, aerrors.Escalate(err, "serializing account actor state")
}
nact := &types.Actor{ nact := &types.Actor{
Code: builtin.AccountActorCodeID, Code: builtin.AccountActorCodeID,
Balance: types.NewInt(0), Balance: types.NewInt(0),
Head: c, Head: EmptyObjectCid,
} }
return nact, nil return nact, nil
} }
func NewSecp256k1AccountActor(st *state.StateTree, addr address.Address) (*types.Actor, aerrors.ActorError) { func NewSecp256k1AccountActor() (*types.Actor, aerrors.ActorError) {
var acstate account.State
acstate.Address = addr
c, err := st.Store.Put(context.TODO(), &acstate)
if err != nil {
return nil, aerrors.Escalate(err, "serializing account actor state")
}
nact := &types.Actor{ nact := &types.Actor{
Code: builtin.AccountActorCodeID, Code: builtin.AccountActorCodeID,
Balance: types.NewInt(0), Balance: types.NewInt(0),
Head: c, Head: EmptyObjectCid,
} }
return nact, nil return nact, nil

View File

@ -281,7 +281,7 @@ func (rs *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMars
params = buf.Bytes() params = buf.Bytes()
} }
ret, err := rs.internalSend(to, method, types.BigInt(value), params) ret, err := rs.internalSend(rs.Message().Receiver(), to, method, types.BigInt(value), params)
if err != nil { if err != nil {
if err.IsFatal() { if err.IsFatal() {
panic(err) panic(err)
@ -292,7 +292,7 @@ func (rs *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMars
return &dumbWrapperType{ret}, 0 return &dumbWrapperType{ret}, 0
} }
func (rt *Runtime) internalSend(to address.Address, method abi.MethodNum, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) { func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) {
ctx, span := trace.StartSpan(rt.ctx, "vmc.Send") ctx, span := trace.StartSpan(rt.ctx, "vmc.Send")
defer span.End() defer span.End()
if span.IsRecordingEvents() { if span.IsRecordingEvents() {
@ -304,7 +304,7 @@ func (rt *Runtime) internalSend(to address.Address, method abi.MethodNum, value
} }
msg := &types.Message{ msg := &types.Message{
From: rt.Message().Receiver(), From: from,
To: to, To: to,
Method: method, Method: method,
Value: value, Value: value,
@ -317,7 +317,6 @@ func (rt *Runtime) internalSend(to address.Address, method abi.MethodNum, value
return nil, aerrors.Fatalf("snapshot failed: %s", err) return nil, aerrors.Fatalf("snapshot failed: %s", err)
} }
defer st.ClearSnapshot() defer st.ClearSnapshot()
rt.ChargeGas(rt.Pricelist().OnMethodInvocation(value, method))
ret, errSend, subrt := rt.vm.send(ctx, msg, rt, 0) ret, errSend, subrt := rt.vm.send(ctx, msg, rt, 0)
if errSend != nil { if errSend != nil {

View File

@ -8,8 +8,6 @@ import (
"testing" "testing"
suites "github.com/filecoin-project/chain-validation/suites" suites "github.com/filecoin-project/chain-validation/suites"
"github.com/filecoin-project/chain-validation/suites/tipset"
factory "github.com/filecoin-project/lotus/chain/validation" factory "github.com/filecoin-project/lotus/chain/validation"
) )
@ -36,7 +34,6 @@ func init() {
// initialize the test skipper with tests being skipped // initialize the test skipper with tests being skipped
TestSuiteSkipper = TestSkipper{testSkips: []suites.TestCase{ TestSuiteSkipper = TestSkipper{testSkips: []suites.TestCase{
/* tests to skip go here */ /* tests to skip go here */
tipset.TestMinerRewardsAndPenalties,
}} }}
} }

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"math/big"
"reflect" "reflect"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
@ -185,7 +184,7 @@ type Rand interface {
type ApplyRet struct { type ApplyRet struct {
types.MessageReceipt types.MessageReceipt
ActorErr aerrors.ActorError ActorErr aerrors.ActorError
Penalty big.Int Penalty types.BigInt
InternalExecutions []*ExecutionResult InternalExecutions []*ExecutionResult
} }
@ -211,25 +210,24 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
}() }()
} }
aerr := rt.chargeGasSafe(rt.Pricelist().OnMethodInvocation(msg.Value, msg.Method))
if aerr != nil {
return nil, aerr, rt
}
toActor, err := st.GetActor(msg.To) toActor, err := st.GetActor(msg.To)
if err != nil { if err != nil {
if xerrors.Is(err, init_.ErrAddressNotFound) { if xerrors.Is(err, init_.ErrAddressNotFound) {
a, err := TryCreateAccountActor(st, msg.To) a, err := TryCreateAccountActor(ctx, rt, msg.To)
if err != nil { if err != nil {
return nil, aerrors.Absorb(err, 1, "could not create account"), rt return nil, aerrors.Absorb(err, 1, "could not create account"), rt
} }
toActor = a toActor = a
gasUsed += PricelistByEpoch(vm.blockHeight).OnCreateActor()
} else { } else {
return nil, aerrors.Escalate(err, "getting actor"), rt return nil, aerrors.Escalate(err, "getting actor"), rt
} }
} }
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 types.BigCmp(msg.Value, types.NewInt(0)) != 0 {
if err := vm.transfer(msg.From, msg.To, msg.Value); err != nil { if err := vm.transfer(msg.From, msg.To, msg.Value); err != nil {
return nil, aerrors.Absorb(err, 1, "failed to transfer funds"), nil return nil, aerrors.Absorb(err, 1, "failed to transfer funds"), nil
@ -263,9 +261,24 @@ func checkMessage(msg *types.Message) error {
return nil return nil
} }
func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) { func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) {
ret, actorErr, _ := vm.send(ctx, msg, nil, 0)
return &ApplyRet{
MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.ExitCode(aerrors.RetCode(actorErr)),
Return: ret,
GasUsed: 0,
},
ActorErr: actorErr,
InternalExecutions: nil,
Penalty: types.NewInt(0),
}, actorErr
}
func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, error) {
ctx, span := trace.StartSpan(ctx, "vm.ApplyMessage") ctx, span := trace.StartSpan(ctx, "vm.ApplyMessage")
defer span.End() defer span.End()
msg := cmsg.VMMessage()
if span.IsRecordingEvents() { if span.IsRecordingEvents() {
span.AddAttributes( span.AddAttributes(
trace.StringAttribute("to", msg.To.String()), trace.StringAttribute("to", msg.To.String()),
@ -279,42 +292,52 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
} }
pl := PricelistByEpoch(vm.blockHeight) pl := PricelistByEpoch(vm.blockHeight)
serMsg, err := msg.Serialize() msgGasCost := pl.OnChainMessage(cmsg.ChainLength())
if err != nil {
return nil, xerrors.Errorf("could not serialize message: %w", err)
}
msgGasCost := pl.OnChainMessage(len(serMsg))
// TODO: charge miner?? // TODO: charge miner??
if msgGasCost > msg.GasLimit { if msgGasCost > msg.GasLimit {
return &ApplyRet{ return &ApplyRet{
MessageReceipt: types.MessageReceipt{ MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrOutOfGas, ExitCode: exitcode.SysErrOutOfGas,
GasUsed: msg.GasLimit, GasUsed: 0,
}, },
Penalty: types.BigMul(msg.GasPrice, types.NewInt(uint64(msgGasCost))),
}, nil }, nil
} }
st := vm.cstate st := vm.cstate
minerPenaltyAmount := types.BigMul(msg.GasPrice, types.NewInt(uint64(msgGasCost)))
fromActor, err := st.GetActor(msg.From) fromActor, err := st.GetActor(msg.From)
if err != nil { if err != nil {
if xerrors.Is(err, types.ErrActorNotFound) { if xerrors.Is(err, types.ErrActorNotFound) {
return &ApplyRet{ return &ApplyRet{
MessageReceipt: types.MessageReceipt{ MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrActorNotFound, ExitCode: exitcode.SysErrActorNotFound,
GasUsed: msg.GasLimit, GasUsed: 0,
}, },
Penalty: minerPenaltyAmount,
}, nil }, nil
} }
return nil, xerrors.Errorf("failed to look up from actor: %w", err) return nil, xerrors.Errorf("failed to look up from actor: %w", err)
} }
if !fromActor.Code.Equals(builtin.AccountActorCodeID) {
return &ApplyRet{
MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrForbidden,
GasUsed: 0,
},
Penalty: minerPenaltyAmount,
}, nil
}
if msg.Nonce != fromActor.Nonce { if msg.Nonce != fromActor.Nonce {
return &ApplyRet{ return &ApplyRet{
MessageReceipt: types.MessageReceipt{ MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrInvalidCallSeqNum, ExitCode: exitcode.SysErrInvalidCallSeqNum,
GasUsed: 0, GasUsed: 0,
}, },
Penalty: minerPenaltyAmount,
}, nil }, nil
} }
@ -324,8 +347,9 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
return &ApplyRet{ return &ApplyRet{
MessageReceipt: types.MessageReceipt{ MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrInsufficientFunds, ExitCode: exitcode.SysErrInsufficientFunds,
GasUsed: msg.GasLimit, GasUsed: 0,
}, },
Penalty: minerPenaltyAmount,
}, nil }, nil
} }
@ -367,21 +391,19 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
var gasUsed int64 var gasUsed int64
if errcode = aerrors.RetCode(actorErr); errcode != 0 { if errcode = aerrors.RetCode(actorErr); errcode != 0 {
gasUsed = msg.GasLimit
// revert all state changes since snapshot // revert all state changes since snapshot
if err := st.Revert(); err != nil { if err := st.Revert(); err != nil {
return nil, xerrors.Errorf("revert state failed: %w", err) return nil, xerrors.Errorf("revert state failed: %w", err)
} }
} else { }
gasUsed = rt.gasUsed gasUsed = rt.gasUsed
if gasUsed < 0 { if gasUsed < 0 {
gasUsed = 0 gasUsed = 0
} }
// refund unused gas // refund unused gas
refund := types.BigMul(types.NewInt(uint64(msg.GasLimit-gasUsed)), msg.GasPrice) refund := types.BigMul(types.NewInt(uint64(msg.GasLimit-gasUsed)), msg.GasPrice)
if err := vm.transferFromGasHolder(msg.From, gasHolder, refund); err != nil { if err := vm.transferFromGasHolder(msg.From, gasHolder, refund); err != nil {
return nil, xerrors.Errorf("failed to refund gas") return nil, xerrors.Errorf("failed to refund gas")
}
} }
gasReward := types.BigMul(msg.GasPrice, types.NewInt(uint64(gasUsed))) gasReward := types.BigMul(msg.GasPrice, types.NewInt(uint64(gasUsed)))
@ -401,6 +423,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
}, },
ActorErr: actorErr, ActorErr: actorErr,
InternalExecutions: rt.internalExecutions, InternalExecutions: rt.internalExecutions,
Penalty: types.NewInt(0),
}, nil }, nil
} }