make state tree snapshots properly stack based

This commit is contained in:
whyrusleeping 2020-03-04 17:19:15 -08:00
parent 5076b2b950
commit 4e9e3f3dc3
6 changed files with 108 additions and 9 deletions

View File

@ -26,7 +26,7 @@ type StateTree struct {
Store cbor.IpldStore
actorcache map[address.Address]*types.Actor
snapshot cid.Cid
snapshots []cid.Cid
}
func NewStateTree(cst cbor.IpldStore) (*StateTree, error) {
@ -134,7 +134,6 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
return cid.Undef, err
}
}
st.actorcache = make(map[address.Address]*types.Actor)
if err := st.root.Flush(ctx); err != nil {
return cid.Undef, err
@ -152,10 +151,14 @@ func (st *StateTree) Snapshot(ctx context.Context) error {
return err
}
st.snapshot = ss
st.snapshots = append(st.snapshots, ss)
return nil
}
func (st *StateTree) ClearSnapshot() {
st.snapshots = st.snapshots[:len(st.snapshots)-1]
}
func (st *StateTree) RegisterNewAddress(addr address.Address, act *types.Actor) (address.Address, error) {
var out address.Address
err := st.MutateActor(builtin.InitActorAddr, func(initact *types.Actor) error {
@ -198,10 +201,12 @@ func (a *AdtStore) Context() context.Context {
var _ adt.Store = (*AdtStore)(nil)
func (st *StateTree) Revert() error {
nd, err := hamt.LoadNode(context.Background(), st.Store, st.snapshot, hamt.UseTreeBitWidth(5))
revTo := st.snapshots[len(st.snapshots)-1]
nd, err := hamt.LoadNode(context.Background(), st.Store, revTo, hamt.UseTreeBitWidth(5))
if err != nil {
return err
}
st.actorcache = make(map[address.Address]*types.Actor)
st.root = nd
return nil

View File

@ -2,9 +2,10 @@ package state
import (
"context"
"github.com/filecoin-project/specs-actors/actors/builtin"
"testing"
"github.com/filecoin-project/specs-actors/actors/builtin"
address "github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/types"
cbor "github.com/ipfs/go-ipld-cbor"
@ -144,3 +145,85 @@ func TestSetCache(t *testing.T) {
t.Error("nonce didn't match")
}
}
func TestSnapshots(t *testing.T) {
ctx := context.Background()
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst)
if err != nil {
t.Fatal(err)
}
var addrs []address.Address
//for _, a := range []string{"t15ocrptbu4i5qucjvvwecihd7fqqgzb27pz5l5zy", "t1dpyvgavvl3f4ujlk6odedss54z6rt5gyuknsuva", "t1feiejbkcvozy7iltt2pxzuoq4d2kpbsusugan7a", "t3rgjfqybjx7bahuhfv7nwfg3tlm4i4zyvldfirjvzm5z5xwjoqbj3rfi2mpmlxpqwxxxafgpkjilqzpg7cefa"} {
for _, a := range []string{"t0100", "t0101", "t0102", "t0103"} {
addr, err := address.NewFromString(a)
if err != nil {
t.Fatal(err)
}
addrs = append(addrs, addr)
}
if err := st.Snapshot(ctx); err != nil {
t.Fatal(err)
}
if err := st.SetActor(addrs[0], &types.Actor{Code: builtin.AccountActorCodeID, Head: builtin.AccountActorCodeID, Balance: types.NewInt(55)}); err != nil {
t.Fatal(err)
}
{ // sub call that will fail
if err := st.Snapshot(ctx); err != nil {
t.Fatal(err)
}
if err := st.SetActor(addrs[1], &types.Actor{Code: builtin.AccountActorCodeID, Head: builtin.AccountActorCodeID, Balance: types.NewInt(77)}); err != nil {
t.Fatal(err)
}
if err := st.Revert(); err != nil {
t.Fatal(err)
}
st.ClearSnapshot()
}
// more operations in top level call...
if err := st.SetActor(addrs[2], &types.Actor{Code: builtin.AccountActorCodeID, Head: builtin.AccountActorCodeID, Balance: types.NewInt(123)}); err != nil {
t.Fatal(err)
}
{ // sub call that succeeds
if err := st.Snapshot(ctx); err != nil {
t.Fatal(err)
}
if err := st.SetActor(addrs[3], &types.Actor{Code: builtin.AccountActorCodeID, Head: builtin.AccountActorCodeID, Balance: types.NewInt(5)}); err != nil {
t.Fatal(err)
}
st.ClearSnapshot()
}
if _, err := st.Flush(ctx); err != nil {
t.Fatal(err)
}
assertHas(t, st, addrs[0])
assertNotHas(t, st, addrs[1])
assertHas(t, st, addrs[2])
assertHas(t, st, addrs[3])
}
func assertHas(t *testing.T, st *StateTree, addr address.Address) {
_, err := st.GetActor(addr)
if err != nil {
t.Fatal(err)
}
}
func assertNotHas(t *testing.T, st *StateTree, addr address.Address) {
_, err := st.GetActor(addr)
if err == nil {
t.Fatal("shouldnt have found actor", addr)
}
}

View File

@ -8,7 +8,6 @@ import (
suites "github.com/filecoin-project/chain-validation/suites"
"github.com/filecoin-project/chain-validation/suites/message"
"github.com/filecoin-project/chain-validation/suites/tipset"
factory "github.com/filecoin-project/lotus/chain/validation"
)
@ -35,7 +34,6 @@ var TestSuiteSkipper TestSkipper
func init() {
// initialize the test skipper with tests being skipped
TestSuiteSkipper = TestSkipper{testSkips: []suites.TestCase{
tipset.TestInternalMessageApplicationFailure,
// Fails due to gas mismatches
message.TestPaych,

View File

@ -163,7 +163,18 @@ func (vmc *VMContext) Send(to address.Address, method abi.MethodNum, value types
GasLimit: vmc.gasAvailable,
}
st := vmc.state
if err := st.Snapshot(ctx); err != nil {
return nil, aerrors.Fatalf("snapshot failed: %s", err)
}
defer st.ClearSnapshot()
ret, err, _ := vmc.vm.send(ctx, msg, vmc, 0)
if err != nil {
if err := st.Revert(); err != nil {
return nil, aerrors.Escalate(err, "failed to revert state tree after failed subcall")
}
}
return ret, err
}
@ -366,6 +377,7 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *VMContext,
gasCharge uint64) ([]byte, aerrors.ActorError, *VMContext) {
st := vm.cstate
fromActor, err := st.GetActor(msg.From)
if err != nil {
return nil, aerrors.Absorb(err, 1, "could not find source actor"), nil
@ -453,6 +465,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
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 {

2
go.mod
View File

@ -116,5 +116,3 @@ replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v
replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi
replace github.com/coreos/go-systemd => github.com/coreos/go-systemd/v22 v22.0.0
replace github.com/filecoin-project/specs-actors => ../specs-actors

2
go.sum
View File

@ -133,6 +133,8 @@ 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 h1:3IojVqJAD5IXMxvZ+WYx+LRbfSB/rOXpYBuHh6o3XkY=
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-20200304210626-21ee86aadcb9 h1:5/XkV9N7Zlidi2RYY/04BToD/XeQrudUseI7Gx6owl8=
github.com/filecoin-project/specs-actors v0.0.0-20200304210626-21ee86aadcb9/go.mod h1:0HAWYrvajFHDgRaKbF0rl+IybVLZL5z4gQ8koCMPhoU=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 h1:EzDjxMg43q1tA2c0MV3tNbaontnHLplHyFF6M5KiVP0=