lotus/chain/state/statetree.go

251 lines
5.7 KiB
Go
Raw Normal View History

package state
2019-07-05 14:29:17 +00:00
import (
"context"
"fmt"
2020-02-25 20:54:58 +00:00
"github.com/filecoin-project/specs-actors/actors/builtin"
2020-02-21 17:13:50 +00:00
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
2019-07-08 12:51:45 +00:00
2020-02-12 07:22:55 +00:00
"github.com/filecoin-project/specs-actors/actors/util/adt"
2019-07-05 14:29:17 +00:00
"github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
2020-02-04 22:19:05 +00:00
cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log/v2"
"go.opencensus.io/trace"
2019-09-10 02:05:24 +00:00
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/types"
2019-07-05 14:29:17 +00:00
)
var log = logging.Logger("statetree")
2019-07-05 14:29:17 +00:00
type StateTree struct {
root *hamt.Node
2020-02-04 22:19:05 +00:00
Store cbor.IpldStore
2019-07-05 14:29:17 +00:00
actorcache map[address.Address]*types.Actor
snapshots []cid.Cid
2019-07-05 14:29:17 +00:00
}
2020-02-04 22:19:05 +00:00
func NewStateTree(cst cbor.IpldStore) (*StateTree, error) {
2019-07-05 14:29:17 +00:00
return &StateTree{
2020-02-14 20:33:41 +00:00
root: hamt.NewNode(cst, hamt.UseTreeBitWidth(5)),
Store: cst,
actorcache: make(map[address.Address]*types.Actor),
2019-07-05 14:29:17 +00:00
}, nil
}
2020-02-04 22:19:05 +00:00
func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
2020-02-14 14:14:39 +00:00
nd, err := hamt.LoadNode(context.Background(), cst, c, hamt.UseTreeBitWidth(5))
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
}
return &StateTree{
root: nd,
Store: cst,
actorcache: make(map[address.Address]*types.Actor),
2019-07-05 14:29:17 +00:00
}, nil
}
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
cact, ok := st.actorcache[addr]
if ok {
if act == cact {
return nil
}
}
st.actorcache[addr] = act
2019-07-05 14:29:17 +00:00
return st.root.Set(context.TODO(), string(addr.Bytes()), act)
}
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-02-25 20:54:58 +00:00
act, err := st.GetActor(builtin.InitActorAddr)
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-02-25 20:35:15 +00:00
var ias init_.State
if err := st.Store.Get(context.TODO(), act.Head, &ias); 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-02-22 13:10:46 +00:00
a, err := ias.ResolveAddress(&AdtStore{st.Store}, addr)
if err != nil {
return address.Undef, xerrors.Errorf("resolve address %s: %w", addr, err)
}
return a, nil
2019-07-05 14:29:17 +00:00
}
func (st *StateTree) GetActor(addr address.Address) (*types.Actor, error) {
if addr == address.Undef {
return nil, fmt.Errorf("GetActor called on undefined address")
}
2019-11-15 16:39:43 +00:00
iaddr, err := st.LookupID(addr)
if err != nil {
2020-02-21 17:13:50 +00:00
if xerrors.Is(err, init_.ErrAddressNotFound) {
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
cact, ok := st.actorcache[addr]
if ok {
return cact, nil
}
2019-09-17 01:56:37 +00:00
var act types.Actor
2019-11-15 16:39:43 +00:00
err = st.root.Find(context.TODO(), string(addr.Bytes()), &act)
2019-07-05 14:29:17 +00:00
if err != nil {
if err == hamt.ErrNotFound {
return nil, types.ErrActorNotFound
2019-07-05 14:29:17 +00:00
}
2019-09-30 23:55:35 +00:00
return nil, xerrors.Errorf("hamt find failed: %w", err)
2019-07-05 14:29:17 +00:00
}
st.actorcache[addr] = &act
return &act, nil
}
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 {
if xerrors.Is(err, init_.ErrAddressNotFound) {
return xerrors.Errorf("resolution lookup failed (%s): %w", addr, err)
}
return xerrors.Errorf("address resolution: %w", err)
}
addr = iaddr
delete(st.actorcache, addr)
if err := st.root.Delete(context.TODO(), string(addr.Bytes())); err != nil {
return xerrors.Errorf("failed to delete actor: %w", err)
}
return nil
}
func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
ctx, span := trace.StartSpan(ctx, "stateTree.Flush")
defer span.End()
2019-07-05 14:29:17 +00:00
for addr, act := range st.actorcache {
if err := st.root.Set(ctx, string(addr.Bytes()), act); err != nil {
2019-07-05 14:29:17 +00:00
return cid.Undef, err
}
}
if err := st.root.Flush(ctx); err != nil {
2019-07-05 14:29:17 +00:00
return cid.Undef, err
}
return st.Store.Put(ctx, st.root)
2019-07-05 14:29:17 +00:00
}
func (st *StateTree) Snapshot(ctx context.Context) error {
ctx, span := trace.StartSpan(ctx, "stateTree.SnapShot")
defer span.End()
ss, err := st.Flush(ctx)
2019-07-05 14:29:17 +00:00
if err != nil {
return err
}
st.snapshots = append(st.snapshots, ss)
2019-07-05 14:29:17 +00:00
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) {
2019-07-05 14:29:17 +00:00
var out address.Address
2020-02-25 20:54:58 +00:00
err := st.MutateActor(builtin.InitActorAddr, func(initact *types.Actor) error {
2020-02-25 20:35:15 +00:00
var ias init_.State
if err := st.Store.Get(context.TODO(), initact.Head, &ias); err != nil {
2019-07-05 14:29:17 +00:00
return err
}
2020-02-18 21:37:59 +00:00
oaddr, err := ias.MapAddressToNewID(&AdtStore{st.Store}, addr)
2019-07-05 14:29:17 +00:00
if err != nil {
return err
}
out = oaddr
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
}
if err := st.SetActor(out, act); 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 {
revTo := st.snapshots[len(st.snapshots)-1]
nd, err := hamt.LoadNode(context.Background(), st.Store, revTo, hamt.UseTreeBitWidth(5))
2019-07-05 14:29:17 +00:00
if err != nil {
return err
}
st.actorcache = make(map[address.Address]*types.Actor)
2019-07-05 14:29:17 +00:00
st.root = nd
return nil
}
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)
}