introduce separate state-tree versions

Instead of versioning the state tree along with the actors, version it
separately. This structure may not upgrade every time we update actors.
This commit is contained in:
Steven Allen 2020-10-06 15:22:54 -07:00
parent 5ef929f130
commit e803cf151f
8 changed files with 73 additions and 39 deletions

View File

@ -26,7 +26,6 @@ import (
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
@ -117,7 +116,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
return nil, nil, xerrors.Errorf("putting empty object: %w", err)
}
state, err := state.NewStateTree(cst, actors.Version0)
state, err := state.NewStateTree(cst, types.StateTreeVersion0)
if err != nil {
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
}

View File

@ -13,6 +13,7 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/chain/actors"
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
cbg "github.com/whyrusleeping/cbor-gen"
@ -26,7 +27,7 @@ var log = logging.Logger("statetree")
// StateTree stores actors state by their ID.
type StateTree struct {
root adt.Map
version actors.Version // TODO
version types.StateTreeVersion
info cid.Cid
Store cbor.IpldStore
@ -120,21 +121,41 @@ func (ss *stateSnaps) deleteActor(addr address.Address) {
ss.layers[len(ss.layers)-1].actors[addr] = streeOp{Delete: true}
}
func NewStateTree(cst cbor.IpldStore, version actors.Version) (*StateTree, error) {
// VersionForNetwork returns the state tree version for the given network
// version.
func VersionForNetwork(ver network.Version) types.StateTreeVersion {
if actors.VersionForNetwork(ver) == actors.Version0 {
return types.StateTreeVersion0
}
return types.StateTreeVersion1
}
func adtForSTVersion(ver types.StateTreeVersion) actors.Version {
switch ver {
case types.StateTreeVersion0:
return actors.Version0
case types.StateTreeVersion1:
return actors.Version2
default:
panic("unhandled state tree version")
}
}
func NewStateTree(cst cbor.IpldStore, ver types.StateTreeVersion) (*StateTree, error) {
var info cid.Cid
switch version {
case actors.Version0:
switch ver {
case types.StateTreeVersion0:
// info is undefined
case actors.Version2:
case types.StateTreeVersion1:
var err error
info, err = cst.Put(context.TODO(), new(types.StateInfo))
info, err = cst.Put(context.TODO(), new(types.StateInfo0))
if err != nil {
return nil, err
}
default:
return nil, xerrors.Errorf("unsupported state tree version: %d", version)
return nil, xerrors.Errorf("unsupported state tree version: %d", ver)
}
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), version)
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), adtForSTVersion(ver))
if err != nil {
return nil, err
}
@ -142,7 +163,7 @@ func NewStateTree(cst cbor.IpldStore, version actors.Version) (*StateTree, error
return &StateTree{
root: root,
info: info,
version: version,
version: ver,
Store: cst,
snaps: newStateSnaps(),
}, nil
@ -154,13 +175,16 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
if err := cst.Get(context.TODO(), c, &root); err != nil {
// We failed to decode as the new version, must be an old version.
root.Actors = c
root.Version = actors.Version0
root.Version = types.StateTreeVersion0
}
switch root.Version {
case actors.Version0, actors.Version2:
case types.StateTreeVersion0, types.StateTreeVersion1:
// Load the actual state-tree HAMT.
nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), root.Actors, actors.Version(root.Version))
nd, err := adt.AsMap(
adt.WrapStore(context.TODO(), cst), root.Actors,
adtForSTVersion(root.Version),
)
if err != nil {
log.Errorf("loading hamt node %s failed: %s", c, err)
return nil, err
@ -169,7 +193,7 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
return &StateTree{
root: nd,
info: root.Info,
version: actors.Version(root.Version),
version: root.Version,
Store: cst,
snaps: newStateSnaps(),
}, nil
@ -309,11 +333,11 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
return cid.Undef, xerrors.Errorf("failed to flush state-tree hamt: %w", err)
}
// If we're version 0, return a raw tree.
if st.version == actors.Version0 {
if st.version == types.StateTreeVersion0 {
return root, nil
}
// Otherwise, return a versioned tree.
return st.Store.Put(ctx, &types.StateRoot{Version: uint64(st.version), Actors: root, Info: st.info})
return st.Store.Put(ctx, &types.StateRoot{Version: st.version, Actors: root, Info: st.info})
}
func (st *StateTree) Snapshot(ctx context.Context) error {
@ -400,7 +424,7 @@ func (st *StateTree) ForEach(f func(address.Address, *types.Actor) error) error
}
// Version returns the version of the StateTree data structure in use.
func (st *StateTree) Version() actors.Version {
func (st *StateTree) Version() types.StateTreeVersion {
return st.version
}

View File

@ -13,13 +13,12 @@ import (
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
)
func BenchmarkStateTreeSet(b *testing.B) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
b.Fatal(err)
}
@ -46,7 +45,7 @@ func BenchmarkStateTreeSet(b *testing.B) {
func BenchmarkStateTreeSetFlush(b *testing.B) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
b.Fatal(err)
}
@ -76,7 +75,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) {
func BenchmarkStateTree10kGetActor(b *testing.B) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
b.Fatal(err)
}
@ -118,7 +117,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) {
func TestSetCache(t *testing.T) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
t.Fatal(err)
}
@ -155,7 +154,7 @@ func TestSetCache(t *testing.T) {
func TestSnapshots(t *testing.T) {
ctx := context.Background()
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
t.Fatal(err)
}
@ -239,7 +238,7 @@ func assertNotHas(t *testing.T, st *StateTree, addr address.Address) {
func TestStateTreeConsistency(t *testing.T) {
cst := cbor.NewMemCborStore()
// TODO: ActorUpgrade: this test tests pre actors v2
st, err := NewStateTree(cst, actors.VersionForNetwork(network.Version3))
st, err := NewStateTree(cst, VersionForNetwork(network.Version3))
if err != nil {
t.Fatal(err)
}

View File

@ -494,7 +494,7 @@ func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, roo
epoch := ts.Height() - 1
info, err := store.Put(ctx, new(types.StateInfo))
info, err := store.Put(ctx, new(types.StateInfo0))
if err != nil {
return cid.Undef, xerrors.Errorf("failed to create new state info for actors v2: %w", err)
}

View File

@ -1648,7 +1648,7 @@ func (t *StateRoot) MarshalCBOR(w io.Writer) error {
scratch := make([]byte, 9)
// t.Version (uint64) (uint64)
// t.Version (types.StateTreeVersion) (uint64)
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Version)); err != nil {
return err
@ -1687,7 +1687,7 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Version (uint64) (uint64)
// t.Version (types.StateTreeVersion) (uint64)
{
@ -1698,7 +1698,7 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.Version = uint64(extra)
t.Version = StateTreeVersion(extra)
}
// t.Actors (cid.Cid) (struct)
@ -1728,22 +1728,22 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
return nil
}
var lengthBufStateInfo = []byte{128}
var lengthBufStateInfo0 = []byte{128}
func (t *StateInfo) MarshalCBOR(w io.Writer) error {
func (t *StateInfo0) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write(lengthBufStateInfo); err != nil {
if _, err := w.Write(lengthBufStateInfo0); err != nil {
return err
}
return nil
}
func (t *StateInfo) UnmarshalCBOR(r io.Reader) error {
*t = StateInfo{}
func (t *StateInfo0) UnmarshalCBOR(r io.Reader) error {
*t = StateInfo0{}
br := cbg.GetPeeker(r)
scratch := make([]byte, 8)

View File

@ -2,9 +2,20 @@ package types
import "github.com/ipfs/go-cid"
// StateTreeVersion is the version of the state tree itself, independent of the
// network version or the actors version.
type StateTreeVersion uint64
const (
// StateTreeVersion0 corresponds to actors < v2.
StateTreeVersion0 StateTreeVersion = iota
// StateTreeVersion1 corresponds to actors >= v2.
StateTreeVersion1
)
type StateRoot struct {
// State root version. Versioned along with actors (for now).
Version uint64
// State tree version.
Version StateTreeVersion
// Actors tree. The structure depends on the state root version.
Actors cid.Cid
// Info. The structure depends on the state root version.
@ -12,4 +23,4 @@ type StateRoot struct {
}
// TODO: version this.
type StateInfo struct{}
type StateInfo0 struct{}

View File

@ -27,7 +27,7 @@ func main() {
types.ExpTipSet{},
types.BeaconEntry{},
types.StateRoot{},
types.StateInfo{},
types.StateInfo0{},
)
if err != nil {
fmt.Println(err)

View File

@ -176,7 +176,8 @@
"CompactPartitions",
"CompactSectorNumbers",
"ConfirmUpdateWorkerKey",
"RepayDebt"
"RepayDebt",
"ChangeOwnerAddress"
],
"fil/2/storagepower": [
"Send",