2019-07-25 22:15:03 +00:00
|
|
|
package state
|
2019-07-05 14:29:17 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2019-07-30 00:46:56 +00:00
|
|
|
"fmt"
|
2020-03-03 23:01:35 +00:00
|
|
|
|
2019-07-05 14:29:17 +00:00
|
|
|
"github.com/ipfs/go-cid"
|
2020-02-04 22:19:05 +00:00
|
|
|
cbor "github.com/ipfs/go-ipld-cbor"
|
2020-01-08 19:10:57 +00:00
|
|
|
logging "github.com/ipfs/go-log/v2"
|
2020-01-22 19:53:06 +00:00
|
|
|
"go.opencensus.io/trace"
|
2019-09-10 02:05:24 +00:00
|
|
|
"golang.org/x/xerrors"
|
2019-07-12 10:23:05 +00:00
|
|
|
|
2019-12-19 20:13:17 +00:00
|
|
|
"github.com/filecoin-project/go-address"
|
2020-09-14 11:14:06 +00:00
|
|
|
"github.com/filecoin-project/go-state-types/abi"
|
2020-09-14 22:43:12 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
2020-09-14 11:14:06 +00:00
|
|
|
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
|
|
|
|
|
|
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
2019-07-05 14:29:17 +00:00
|
|
|
)
|
|
|
|
|
2019-07-25 22:15:03 +00:00
|
|
|
var log = logging.Logger("statetree")
|
|
|
|
|
2020-06-02 14:29:39 +00:00
|
|
|
// StateTree stores actors state by their ID.
|
2019-07-05 14:29:17 +00:00
|
|
|
type StateTree struct {
|
2020-09-14 22:43:12 +00:00
|
|
|
root adt.Map
|
|
|
|
version builtin.Version // TODO
|
|
|
|
info cid.Cid
|
|
|
|
Store cbor.IpldStore
|
2019-07-05 14:29:17 +00:00
|
|
|
|
2020-04-03 00:09:41 +00:00
|
|
|
snaps *stateSnaps
|
|
|
|
}
|
|
|
|
|
|
|
|
type stateSnaps struct {
|
2020-04-03 23:26:52 +00:00
|
|
|
layers []*stateSnapLayer
|
|
|
|
}
|
|
|
|
|
|
|
|
type stateSnapLayer struct {
|
|
|
|
actors map[address.Address]streeOp
|
|
|
|
resolveCache map[address.Address]address.Address
|
|
|
|
}
|
|
|
|
|
|
|
|
func newStateSnapLayer() *stateSnapLayer {
|
|
|
|
return &stateSnapLayer{
|
|
|
|
actors: make(map[address.Address]streeOp),
|
|
|
|
resolveCache: make(map[address.Address]address.Address),
|
|
|
|
}
|
2020-04-03 00:09:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type streeOp struct {
|
|
|
|
Act types.Actor
|
|
|
|
Delete bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func newStateSnaps() *stateSnaps {
|
2020-04-03 23:26:52 +00:00
|
|
|
ss := &stateSnaps{}
|
|
|
|
ss.addLayer()
|
|
|
|
return ss
|
2020-04-03 00:09:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ss *stateSnaps) addLayer() {
|
2020-04-03 23:26:52 +00:00
|
|
|
ss.layers = append(ss.layers, newStateSnapLayer())
|
2020-04-03 00:09:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ss *stateSnaps) dropLayer() {
|
2020-04-03 01:20:49 +00:00
|
|
|
ss.layers[len(ss.layers)-1] = nil // allow it to be GCed
|
2020-04-03 00:09:41 +00:00
|
|
|
ss.layers = ss.layers[:len(ss.layers)-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ss *stateSnaps) mergeLastLayer() {
|
|
|
|
last := ss.layers[len(ss.layers)-1]
|
|
|
|
nextLast := ss.layers[len(ss.layers)-2]
|
|
|
|
|
2020-04-03 23:26:52 +00:00
|
|
|
for k, v := range last.actors {
|
|
|
|
nextLast.actors[k] = v
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, v := range last.resolveCache {
|
|
|
|
nextLast.resolveCache[k] = v
|
2020-04-03 00:09:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ss.dropLayer()
|
|
|
|
}
|
|
|
|
|
2020-04-03 23:26:52 +00:00
|
|
|
func (ss *stateSnaps) resolveAddress(addr address.Address) (address.Address, bool) {
|
|
|
|
for i := len(ss.layers) - 1; i >= 0; i-- {
|
|
|
|
resa, ok := ss.layers[i].resolveCache[addr]
|
|
|
|
if ok {
|
|
|
|
return resa, true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return address.Undef, false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ss *stateSnaps) cacheResolveAddress(addr, resa address.Address) {
|
|
|
|
ss.layers[len(ss.layers)-1].resolveCache[addr] = resa
|
|
|
|
}
|
|
|
|
|
2020-04-03 00:09:41 +00:00
|
|
|
func (ss *stateSnaps) getActor(addr address.Address) (*types.Actor, error) {
|
|
|
|
for i := len(ss.layers) - 1; i >= 0; i-- {
|
2020-04-03 23:26:52 +00:00
|
|
|
act, ok := ss.layers[i].actors[addr]
|
2020-04-03 00:09:41 +00:00
|
|
|
if ok {
|
|
|
|
if act.Delete {
|
|
|
|
return nil, types.ErrActorNotFound
|
|
|
|
}
|
|
|
|
|
|
|
|
return &act.Act, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ss *stateSnaps) setActor(addr address.Address, act *types.Actor) {
|
2020-04-03 23:26:52 +00:00
|
|
|
ss.layers[len(ss.layers)-1].actors[addr] = streeOp{Act: *act}
|
2020-04-03 00:09:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ss *stateSnaps) deleteActor(addr address.Address) {
|
2020-04-03 23:26:52 +00:00
|
|
|
ss.layers[len(ss.layers)-1].actors[addr] = streeOp{Delete: true}
|
2019-07-05 14:29:17 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 22:43:12 +00:00
|
|
|
func NewStateTree(cst cbor.IpldStore, version builtin.Version) (*StateTree, error) {
|
|
|
|
var info cid.Cid
|
|
|
|
switch version {
|
|
|
|
case builtin.Version0:
|
|
|
|
// info is undefined
|
|
|
|
default:
|
|
|
|
return nil, xerrors.Errorf("unsupported state tree version: %d", version)
|
|
|
|
}
|
2020-09-14 11:14:06 +00:00
|
|
|
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), version)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-23 00:14:54 +00:00
|
|
|
|
2019-07-05 14:29:17 +00:00
|
|
|
return &StateTree{
|
2020-09-14 22:43:12 +00:00
|
|
|
root: root,
|
|
|
|
info: info,
|
|
|
|
version: version,
|
|
|
|
Store: cst,
|
|
|
|
snaps: newStateSnaps(),
|
2019-07-05 14:29:17 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2020-09-14 22:43:12 +00:00
|
|
|
func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
|
|
|
|
var root types.StateRoot
|
|
|
|
// Try loading as a new-style state-tree (version/actors tuple).
|
|
|
|
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 = builtin.Version0
|
|
|
|
}
|
|
|
|
|
|
|
|
// If that fails, load as an old-style state-tree (direct hampt, version 0.
|
|
|
|
nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), root.Actors, builtin.Version(root.Version))
|
2019-07-05 14:29:17 +00:00
|
|
|
if err != nil {
|
2019-07-30 16:04:36 +00:00
|
|
|
log.Errorf("loading hamt node %s failed: %s", c, err)
|
2019-07-05 14:29:17 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-09-14 22:43:12 +00:00
|
|
|
switch root.Version {
|
|
|
|
case builtin.Version0:
|
|
|
|
// supported
|
|
|
|
default:
|
|
|
|
return nil, xerrors.Errorf("unsupported state tree version: %d", root.Version)
|
|
|
|
}
|
|
|
|
|
2019-07-05 14:29:17 +00:00
|
|
|
return &StateTree{
|
2020-09-14 22:43:12 +00:00
|
|
|
root: nd,
|
|
|
|
info: root.Info,
|
|
|
|
version: builtin.Version(root.Version),
|
|
|
|
Store: cst,
|
|
|
|
snaps: newStateSnaps(),
|
2019-07-05 14:29:17 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2019-07-12 10:23:05 +00:00
|
|
|
func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error {
|
2019-11-15 16:39:43 +00:00
|
|
|
iaddr, err := st.LookupID(addr)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("ID lookup failed: %w", err)
|
2019-07-05 14:29:17 +00:00
|
|
|
}
|
2019-11-15 16:39:43 +00:00
|
|
|
addr = iaddr
|
2019-07-05 14:29:17 +00:00
|
|
|
|
2020-04-03 00:09:41 +00:00
|
|
|
st.snaps.setActor(addr, act)
|
|
|
|
return nil
|
2019-07-05 14:29:17 +00:00
|
|
|
}
|
|
|
|
|
2020-06-02 14:29:39 +00:00
|
|
|
// LookupID gets the ID address of this actor's `addr` stored in the `InitActor`.
|
2019-11-15 16:39:43 +00:00
|
|
|
func (st *StateTree) LookupID(addr address.Address) (address.Address, error) {
|
|
|
|
if addr.Protocol() == address.ID {
|
|
|
|
return addr, nil
|
|
|
|
}
|
|
|
|
|
2020-04-03 23:26:52 +00:00
|
|
|
resa, ok := st.snaps.resolveAddress(addr)
|
|
|
|
if ok {
|
|
|
|
return resa, nil
|
|
|
|
}
|
|
|
|
|
2020-09-14 22:43:12 +00:00
|
|
|
act, err := st.GetActor(init_.Address)
|
2019-07-05 14:29:17 +00:00
|
|
|
if err != nil {
|
2019-09-10 02:05:24 +00:00
|
|
|
return address.Undef, xerrors.Errorf("getting init actor: %w", err)
|
2019-07-05 14:29:17 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 11:14:06 +00:00
|
|
|
ias, err := init_.Load(&AdtStore{st.Store}, act)
|
2020-09-12 03:07:52 +00:00
|
|
|
if err != nil {
|
2019-09-10 02:05:24 +00:00
|
|
|
return address.Undef, xerrors.Errorf("loading init actor state: %w", err)
|
2019-07-05 14:29:17 +00:00
|
|
|
}
|
|
|
|
|
2020-09-12 03:07:52 +00:00
|
|
|
a, found, err := ias.ResolveAddress(addr)
|
2020-08-12 02:47:24 +00:00
|
|
|
if err == nil && !found {
|
|
|
|
err = types.ErrActorNotFound
|
|
|
|
}
|
2020-02-22 13:10:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return address.Undef, xerrors.Errorf("resolve address %s: %w", addr, err)
|
|
|
|
}
|
2020-04-03 23:26:52 +00:00
|
|
|
|
|
|
|
st.snaps.cacheResolveAddress(addr, a)
|
|
|
|
|
2020-02-22 13:10:46 +00:00
|
|
|
return a, nil
|
2019-07-05 14:29:17 +00:00
|
|
|
}
|
|
|
|
|
2020-02-18 18:10:42 +00:00
|
|
|
// GetActor returns the actor from any type of `addr` provided.
|
2019-07-12 10:23:05 +00:00
|
|
|
func (st *StateTree) GetActor(addr address.Address) (*types.Actor, error) {
|
2019-07-30 00:46:56 +00:00
|
|
|
if addr == address.Undef {
|
|
|
|
return nil, fmt.Errorf("GetActor called on undefined address")
|
|
|
|
}
|
|
|
|
|
2020-02-18 18:10:42 +00:00
|
|
|
// Transform `addr` to its ID format.
|
2019-11-15 16:39:43 +00:00
|
|
|
iaddr, err := st.LookupID(addr)
|
|
|
|
if err != nil {
|
2020-08-12 02:47:24 +00:00
|
|
|
if xerrors.Is(err, types.ErrActorNotFound) {
|
2020-02-22 13:10:46 +00:00
|
|
|
return nil, xerrors.Errorf("resolution lookup failed (%s): %w", addr, err)
|
2019-07-05 14:29:17 +00:00
|
|
|
}
|
2019-11-15 16:39:43 +00:00
|
|
|
return nil, xerrors.Errorf("address resolution: %w", err)
|
2019-07-05 14:29:17 +00:00
|
|
|
}
|
2019-11-15 16:39:43 +00:00
|
|
|
addr = iaddr
|
2019-07-05 14:29:17 +00:00
|
|
|
|
2020-04-03 00:09:41 +00:00
|
|
|
snapAct, err := st.snaps.getActor(addr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if snapAct != nil {
|
|
|
|
return snapAct, nil
|
2019-07-05 14:29:17 +00:00
|
|
|
}
|
|
|
|
|
2019-09-17 01:56:37 +00:00
|
|
|
var act types.Actor
|
2020-09-14 11:14:06 +00:00
|
|
|
if found, err := st.root.Get(abi.AddrKey(addr), &act); err != nil {
|
2019-09-30 23:55:35 +00:00
|
|
|
return nil, xerrors.Errorf("hamt find failed: %w", err)
|
2020-07-23 00:14:54 +00:00
|
|
|
} else if !found {
|
|
|
|
return nil, types.ErrActorNotFound
|
2019-07-05 14:29:17 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 00:09:41 +00:00
|
|
|
st.snaps.setActor(addr, &act)
|
2019-07-05 14:29:17 +00:00
|
|
|
|
|
|
|
return &act, nil
|
|
|
|
}
|
|
|
|
|
2020-03-10 02:24:02 +00:00
|
|
|
func (st *StateTree) DeleteActor(addr address.Address) error {
|
|
|
|
if addr == address.Undef {
|
|
|
|
return xerrors.Errorf("DeleteActor called on undefined address")
|
|
|
|
}
|
|
|
|
|
|
|
|
iaddr, err := st.LookupID(addr)
|
|
|
|
if err != nil {
|
2020-08-12 02:47:24 +00:00
|
|
|
if xerrors.Is(err, types.ErrActorNotFound) {
|
2020-03-10 02:24:02 +00:00
|
|
|
return xerrors.Errorf("resolution lookup failed (%s): %w", addr, err)
|
|
|
|
}
|
|
|
|
return xerrors.Errorf("address resolution: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
addr = iaddr
|
|
|
|
|
2020-04-03 00:09:41 +00:00
|
|
|
_, err = st.GetActor(addr)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2020-03-10 02:24:02 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 00:09:41 +00:00
|
|
|
st.snaps.deleteActor(addr)
|
|
|
|
|
2020-03-10 02:24:02 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-01-22 19:53:06 +00:00
|
|
|
func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
|
2020-08-20 04:49:10 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "stateTree.Flush") //nolint:staticcheck
|
2020-01-22 19:53:06 +00:00
|
|
|
defer span.End()
|
2020-04-03 00:09:41 +00:00
|
|
|
if len(st.snaps.layers) != 1 {
|
|
|
|
return cid.Undef, xerrors.Errorf("tried to flush state tree with snapshots on the stack")
|
|
|
|
}
|
2020-01-22 19:53:06 +00:00
|
|
|
|
2020-04-03 23:26:52 +00:00
|
|
|
for addr, sto := range st.snaps.layers[0].actors {
|
2020-04-03 00:09:41 +00:00
|
|
|
if sto.Delete {
|
2020-09-14 11:14:06 +00:00
|
|
|
if err := st.root.Delete(abi.AddrKey(addr)); err != nil {
|
2020-04-03 00:09:41 +00:00
|
|
|
return cid.Undef, err
|
|
|
|
}
|
|
|
|
} else {
|
2020-09-14 11:14:06 +00:00
|
|
|
if err := st.root.Put(abi.AddrKey(addr), &sto.Act); err != nil {
|
2020-04-03 00:09:41 +00:00
|
|
|
return cid.Undef, err
|
|
|
|
}
|
2019-07-05 14:29:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-14 22:43:12 +00:00
|
|
|
root, err := st.root.Root()
|
|
|
|
if err != nil {
|
|
|
|
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 == builtin.Version0 {
|
|
|
|
return root, nil
|
|
|
|
}
|
|
|
|
// Otherwise, return a versioned tree.
|
|
|
|
return st.Store.Put(ctx, &types.StateRoot{Version: uint64(st.version), Actors: root, Info: st.info})
|
2019-07-05 14:29:17 +00:00
|
|
|
}
|
|
|
|
|
2020-01-22 19:53:06 +00:00
|
|
|
func (st *StateTree) Snapshot(ctx context.Context) error {
|
2020-08-20 04:49:10 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "stateTree.SnapShot") //nolint:staticcheck
|
2020-01-22 19:53:06 +00:00
|
|
|
defer span.End()
|
|
|
|
|
2020-04-03 00:09:41 +00:00
|
|
|
st.snaps.addLayer()
|
2019-07-05 14:29:17 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-03-05 01:19:15 +00:00
|
|
|
func (st *StateTree) ClearSnapshot() {
|
2020-04-03 00:09:41 +00:00
|
|
|
st.snaps.mergeLastLayer()
|
2020-03-05 01:19:15 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 02:25:20 +00:00
|
|
|
func (st *StateTree) RegisterNewAddress(addr address.Address) (address.Address, error) {
|
2019-07-05 14:29:17 +00:00
|
|
|
var out address.Address
|
2020-09-14 22:43:12 +00:00
|
|
|
err := st.MutateActor(init_.Address, func(initact *types.Actor) error {
|
2020-09-14 11:14:06 +00:00
|
|
|
ias, err := init_.Load(&AdtStore{st.Store}, initact)
|
2020-09-12 03:07:52 +00:00
|
|
|
if err != nil {
|
2019-07-05 14:29:17 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-09-12 03:07:52 +00:00
|
|
|
oaddr, err := ias.MapAddressToNewID(addr)
|
2019-07-05 14:29:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
out = oaddr
|
|
|
|
|
2020-09-12 03:07:52 +00:00
|
|
|
ncid, err := st.Store.Put(context.TODO(), ias)
|
2019-07-05 14:29:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
initact.Head = ncid
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return address.Undef, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
2020-02-18 21:37:59 +00:00
|
|
|
type AdtStore struct{ cbor.IpldStore }
|
2020-02-12 07:22:55 +00:00
|
|
|
|
2020-02-18 21:37:59 +00:00
|
|
|
func (a *AdtStore) Context() context.Context {
|
2020-02-12 07:22:55 +00:00
|
|
|
return context.TODO()
|
|
|
|
}
|
|
|
|
|
2020-02-18 21:37:59 +00:00
|
|
|
var _ adt.Store = (*AdtStore)(nil)
|
2020-02-12 07:22:55 +00:00
|
|
|
|
2019-07-05 14:29:17 +00:00
|
|
|
func (st *StateTree) Revert() error {
|
2020-04-03 00:09:41 +00:00
|
|
|
st.snaps.dropLayer()
|
|
|
|
st.snaps.addLayer()
|
2019-07-05 14:29:17 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-07-12 10:23:05 +00:00
|
|
|
func (st *StateTree) MutateActor(addr address.Address, f func(*types.Actor) error) error {
|
2019-07-05 14:29:17 +00:00
|
|
|
act, err := st.GetActor(addr)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := f(act); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return st.SetActor(addr, act)
|
|
|
|
}
|
2020-08-12 22:20:32 +00:00
|
|
|
|
|
|
|
func (st *StateTree) ForEach(f func(address.Address, *types.Actor) error) error {
|
|
|
|
var act types.Actor
|
|
|
|
return st.root.ForEach(&act, func(k string) error {
|
|
|
|
addr, err := address.NewFromBytes([]byte(k))
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("invalid address (%x) found in state tree key: %w", []byte(k), err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return f(addr, &act)
|
|
|
|
})
|
|
|
|
}
|