Merge pull request #2539 from Stebalien/feat/use-adt

Refactor to use actor adt types instead of directly using HAMTs and AMTs
This commit is contained in:
Łukasz Magiera 2020-07-23 20:42:32 +02:00 committed by GitHub
commit e5977658f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 287 additions and 311 deletions

View File

@ -10,12 +10,10 @@ import (
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
ds "github.com/ipfs/go-datastore" ds "github.com/ipfs/go-datastore"
ds_sync "github.com/ipfs/go-datastore/sync" ds_sync "github.com/ipfs/go-datastore/sync"
"github.com/ipfs/go-hamt-ipld"
bstore "github.com/ipfs/go-ipfs-blockstore" bstore "github.com/ipfs/go-ipfs-blockstore"
cbornode "github.com/ipfs/go-ipld-cbor" cbornode "github.com/ipfs/go-ipld-cbor"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/market"
@ -69,7 +67,7 @@ func (m mockAPI) setActor(tsk types.TipSetKey, act *types.Actor) {
func TestMarketPredicates(t *testing.T) { func TestMarketPredicates(t *testing.T) {
ctx := context.Background() ctx := context.Background()
bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore())) bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore()))
store := cbornode.NewCborStore(bs) store := adt.WrapStore(ctx, cbornode.NewCborStore(bs))
oldDeal1 := &market.DealState{ oldDeal1 := &market.DealState{
SectorStartEpoch: 1, SectorStartEpoch: 1,
@ -284,7 +282,7 @@ func TestMarketPredicates(t *testing.T) {
func TestMinerSectorChange(t *testing.T) { func TestMinerSectorChange(t *testing.T) {
ctx := context.Background() ctx := context.Background()
bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore())) bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore()))
store := cbornode.NewCborStore(bs) store := adt.WrapStore(ctx, cbornode.NewCborStore(bs))
nextID := uint64(0) nextID := uint64(0)
nextIDAddrF := func() address.Address { nextIDAddrF := func() address.Address {
@ -376,7 +374,7 @@ func mockTipset(minerAddr address.Address, timestamp uint64) (*types.TipSet, err
}}) }})
} }
func createMarketState(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, deals map[abi.DealID]*market.DealState, props map[abi.DealID]*market.DealProposal) cid.Cid { func createMarketState(ctx context.Context, t *testing.T, store adt.Store, deals map[abi.DealID]*market.DealState, props map[abi.DealID]*market.DealProposal) cid.Cid {
dealRootCid := createDealAMT(ctx, t, store, deals) dealRootCid := createDealAMT(ctx, t, store, deals)
propRootCid := createProposalAMT(ctx, t, store, props) propRootCid := createProposalAMT(ctx, t, store, props)
@ -389,37 +387,37 @@ func createMarketState(ctx context.Context, t *testing.T, store *cbornode.BasicI
return stateC return stateC
} }
func createEmptyMarketState(t *testing.T, store *cbornode.BasicIpldStore) *market.State { func createEmptyMarketState(t *testing.T, store adt.Store) *market.State {
emptyArrayCid, err := amt.NewAMT(store).Flush(context.TODO()) emptyArrayCid, err := adt.MakeEmptyArray(store).Root()
require.NoError(t, err) require.NoError(t, err)
emptyMap, err := store.Put(context.TODO(), hamt.NewNode(store, hamt.UseTreeBitWidth(5))) emptyMap, err := adt.MakeEmptyMap(store).Root()
require.NoError(t, err) require.NoError(t, err)
return market.ConstructState(emptyArrayCid, emptyMap, emptyMap) return market.ConstructState(emptyArrayCid, emptyMap, emptyMap)
} }
func createDealAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, deals map[abi.DealID]*market.DealState) cid.Cid { func createDealAMT(ctx context.Context, t *testing.T, store adt.Store, deals map[abi.DealID]*market.DealState) cid.Cid {
root := amt.NewAMT(store) root := adt.MakeEmptyArray(store)
for dealID, dealState := range deals { for dealID, dealState := range deals {
err := root.Set(ctx, uint64(dealID), dealState) err := root.Set(uint64(dealID), dealState)
require.NoError(t, err) require.NoError(t, err)
} }
rootCid, err := root.Flush(ctx) rootCid, err := root.Root()
require.NoError(t, err) require.NoError(t, err)
return rootCid return rootCid
} }
func createProposalAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, props map[abi.DealID]*market.DealProposal) cid.Cid { func createProposalAMT(ctx context.Context, t *testing.T, store adt.Store, props map[abi.DealID]*market.DealProposal) cid.Cid {
root := amt.NewAMT(store) root := adt.MakeEmptyArray(store)
for dealID, prop := range props { for dealID, prop := range props {
err := root.Set(ctx, uint64(dealID), prop) err := root.Set(uint64(dealID), prop)
require.NoError(t, err) require.NoError(t, err)
} }
rootCid, err := root.Flush(ctx) rootCid, err := root.Root()
require.NoError(t, err) require.NoError(t, err)
return rootCid return rootCid
} }
func createMinerState(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, owner, worker address.Address, sectors []miner.SectorOnChainInfo) cid.Cid { func createMinerState(ctx context.Context, t *testing.T, store adt.Store, owner, worker address.Address, sectors []miner.SectorOnChainInfo) cid.Cid {
rootCid := createSectorsAMT(ctx, t, store, sectors) rootCid := createSectorsAMT(ctx, t, store, sectors)
state := createEmptyMinerState(ctx, t, store, owner, worker) state := createEmptyMinerState(ctx, t, store, owner, worker)
@ -430,10 +428,10 @@ func createMinerState(ctx context.Context, t *testing.T, store *cbornode.BasicIp
return stateC return stateC
} }
func createEmptyMinerState(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, owner, worker address.Address) *miner.State { func createEmptyMinerState(ctx context.Context, t *testing.T, store adt.Store, owner, worker address.Address) *miner.State {
emptyArrayCid, err := amt.NewAMT(store).Flush(context.TODO()) emptyArrayCid, err := adt.MakeEmptyArray(store).Root()
require.NoError(t, err) require.NoError(t, err)
emptyMap, err := store.Put(context.TODO(), hamt.NewNode(store, hamt.UseTreeBitWidth(5))) emptyMap, err := adt.MakeEmptyMap(store).Root()
require.NoError(t, err) require.NoError(t, err)
emptyDeadline, err := store.Put(context.TODO(), &miner.Deadline{ emptyDeadline, err := store.Put(context.TODO(), &miner.Deadline{
@ -457,14 +455,14 @@ func createEmptyMinerState(ctx context.Context, t *testing.T, store *cbornode.Ba
} }
func createSectorsAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, sectors []miner.SectorOnChainInfo) cid.Cid { func createSectorsAMT(ctx context.Context, t *testing.T, store adt.Store, sectors []miner.SectorOnChainInfo) cid.Cid {
root := amt.NewAMT(store) root := adt.MakeEmptyArray(store)
for _, sector := range sectors { for _, sector := range sectors {
sector := sector sector := sector
err := root.Set(ctx, uint64(sector.SectorNumber), &sector) err := root.Set(uint64(sector.SectorNumber), &sector)
require.NoError(t, err) require.NoError(t, err)
} }
rootCid, err := root.Flush(ctx) rootCid, err := root.Root()
require.NoError(t, err) require.NoError(t, err)
return rootCid return rootCid
} }

View File

@ -12,7 +12,6 @@ import (
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/abi/big"
@ -358,9 +357,8 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB
return nil, xerrors.Errorf("setup miners failed: %w", err) return nil, xerrors.Errorf("setup miners failed: %w", err)
} }
cst := cbor.NewCborStore(bs) store := adt.WrapStore(ctx, cbor.NewCborStore(bs))
emptyroot, err := adt.MakeEmptyArray(store).Root()
emptyroot, err := amt.FromArray(ctx, cst, nil)
if err != nil { if err != nil {
return nil, xerrors.Errorf("amt build failed: %w", err) return nil, xerrors.Errorf("amt build failed: %w", err)
} }

View File

@ -6,11 +6,12 @@ import (
"fmt" "fmt"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/util/adt"
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
"github.com/ipfs/go-hamt-ipld"
bstore "github.com/ipfs/go-ipfs-blockstore" bstore "github.com/ipfs/go-ipfs-blockstore"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
@ -26,8 +27,8 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
ias.NextID = MinerStart ias.NextID = MinerStart
ias.NetworkName = netname ias.NetworkName = netname
cst := cbor.NewCborStore(bs) store := adt.WrapStore(context.TODO(), cbor.NewCborStore(bs))
amap := hamt.NewNode(cst, hamt.UseTreeBitWidth(5)) // TODO: use spec adt map amap := adt.MakeEmptyMap(store)
for i, a := range initialActors { for i, a := range initialActors {
if a.Type == genesis.TMultisig { if a.Type == genesis.TMultisig {
@ -43,28 +44,26 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
return nil, xerrors.Errorf("unmarshaling account meta: %w", err) return nil, xerrors.Errorf("unmarshaling account meta: %w", err)
} }
fmt.Printf("init set %s t0%d\n", ainfo.Owner, AccountStart+uint64(i)) fmt.Printf("init set %s t0%d\n", ainfo.Owner, AccountStart+int64(i))
if err := amap.Set(context.TODO(), string(ainfo.Owner.Bytes()), AccountStart+uint64(i)); err != nil { value := cbg.CborInt(AccountStart + int64(i))
if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil {
return nil, err return nil, err
} }
} }
if err := amap.Set(context.TODO(), string(RootVerifierAddr.Bytes()), 80); err != nil { value := cbg.CborInt(80)
if err := amap.Put(adt.AddrKey(RootVerifierAddr), &value); err != nil {
return nil, err return nil, err
} }
if err := amap.Flush(context.TODO()); err != nil { amapaddr, err := amap.Root()
return nil, err
}
amapcid, err := cst.Put(context.TODO(), amap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ias.AddressMap = amapaddr
ias.AddressMap = amapcid statecid, err := store.Put(store.Context(), &ias)
statecid, err := cst.Put(context.TODO(), &ias)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -2,11 +2,12 @@ package genesis
import ( import (
"context" "context"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/ipfs/go-hamt-ipld"
bstore "github.com/ipfs/go-ipfs-blockstore" bstore "github.com/ipfs/go-ipfs-blockstore"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
@ -14,10 +15,8 @@ import (
) )
func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) { func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) {
ctx := context.TODO() store := adt.WrapStore(context.TODO(), cbor.NewCborStore(bs))
cst := cbor.NewCborStore(bs) emptyhamt, err := adt.MakeEmptyMap(store).Root()
nd := hamt.NewNode(cst, hamt.UseTreeBitWidth(5))
emptyhamt, err := cst.Put(ctx, nd)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -36,7 +35,7 @@ func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) {
ProofValidationBatch: nil, ProofValidationBatch: nil,
} }
stcid, err := cst.Put(ctx, sms) stcid, err := store.Put(store.Context(), sms)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -2,11 +2,10 @@ package genesis
import ( import (
"context" "context"
"github.com/ipfs/go-hamt-ipld"
"github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/market"
"github.com/filecoin-project/specs-actors/actors/util/adt"
bstore "github.com/ipfs/go-ipfs-blockstore" bstore "github.com/ipfs/go-ipfs-blockstore"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
@ -14,20 +13,20 @@ import (
) )
func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) { func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) {
cst := cbor.NewCborStore(bs) store := adt.WrapStore(context.TODO(), cbor.NewCborStore(bs))
a, err := amt.NewAMT(cst).Flush(context.TODO()) a, err := adt.MakeEmptyArray(store).Root()
if err != nil { if err != nil {
return nil, err return nil, err
} }
h, err := cst.Put(context.TODO(), hamt.NewNode(cst, hamt.UseTreeBitWidth(5))) h, err := adt.MakeEmptyMap(store).Root()
if err != nil { if err != nil {
return nil, err return nil, err
} }
sms := market.ConstructState(a, h, h) sms := market.ConstructState(a, h, h)
stcid, err := cst.Put(context.TODO(), sms) stcid, err := store.Put(store.Context(), sms)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -4,12 +4,12 @@ import (
"context" "context"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/ipfs/go-hamt-ipld"
bstore "github.com/ipfs/go-ipfs-blockstore" bstore "github.com/ipfs/go-ipfs-blockstore"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
) )
@ -35,16 +35,16 @@ func init() {
} }
func SetupVerifiedRegistryActor(bs bstore.Blockstore) (*types.Actor, error) { func SetupVerifiedRegistryActor(bs bstore.Blockstore) (*types.Actor, error) {
cst := cbor.NewCborStore(bs) store := adt.WrapStore(context.TODO(), cbor.NewCborStore(bs))
h, err := cst.Put(context.TODO(), hamt.NewNode(cst, hamt.UseTreeBitWidth(5))) h, err := adt.MakeEmptyMap(store).Root()
if err != nil { if err != nil {
return nil, err return nil, err
} }
sms := verifreg.ConstructState(h, RootVerifierID) sms := verifreg.ConstructState(h, RootVerifierID)
stcid, err := cst.Put(context.TODO(), sms) stcid, err := store.Put(store.Context(), sms)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -4,8 +4,8 @@ import (
"context" "context"
bls "github.com/filecoin-project/filecoin-ffi" bls "github.com/filecoin-project/filecoin-ffi"
amt "github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/specs-actors/actors/util/adt"
cid "github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
@ -78,17 +78,17 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
} }
} }
bs := cbor.NewCborStore(sm.ChainStore().Blockstore()) store := sm.ChainStore().Store(ctx)
blsmsgroot, err := amt.FromArray(ctx, bs, toIfArr(blsMsgCids)) blsmsgroot, err := toArray(store, blsMsgCids)
if err != nil { if err != nil {
return nil, xerrors.Errorf("building bls amt: %w", err) return nil, xerrors.Errorf("building bls amt: %w", err)
} }
secpkmsgroot, err := amt.FromArray(ctx, bs, toIfArr(secpkMsgCids)) secpkmsgroot, err := toArray(store, secpkMsgCids)
if err != nil { if err != nil {
return nil, xerrors.Errorf("building secpk amt: %w", err) return nil, xerrors.Errorf("building secpk amt: %w", err)
} }
mmcid, err := bs.Put(ctx, &types.MsgMeta{ mmcid, err := store.Put(store.Context(), &types.MsgMeta{
BlsMessages: blsmsgroot, BlsMessages: blsmsgroot,
SecpkMessages: secpkmsgroot, SecpkMessages: secpkmsgroot,
}) })
@ -167,11 +167,13 @@ func aggregateSignatures(sigs []crypto.Signature) (*crypto.Signature, error) {
}, nil }, nil
} }
func toIfArr(cids []cid.Cid) []cbg.CBORMarshaler { func toArray(store adt.Store, cids []cid.Cid) (cid.Cid, error) {
out := make([]cbg.CBORMarshaler, 0, len(cids)) arr := adt.MakeEmptyArray(store)
for _, c := range cids { for i, c := range cids {
oc := cbg.CborCid(c) oc := cbg.CborCid(c)
out = append(out, &oc) if err := arr.Set(uint64(i), &oc); err != nil {
return cid.Undef, err
} }
return out }
return arr.Root()
} }

View File

@ -9,7 +9,6 @@ import (
"github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
"go.opencensus.io/trace" "go.opencensus.io/trace"
@ -23,7 +22,7 @@ var log = logging.Logger("statetree")
// StateTree stores actors state by their ID. // StateTree stores actors state by their ID.
type StateTree struct { type StateTree struct {
root *hamt.Node root *adt.Map
Store cbor.IpldStore Store cbor.IpldStore
snaps *stateSnaps snaps *stateSnaps
@ -117,15 +116,16 @@ func (ss *stateSnaps) deleteActor(addr address.Address) {
} }
func NewStateTree(cst cbor.IpldStore) (*StateTree, error) { func NewStateTree(cst cbor.IpldStore) (*StateTree, error) {
return &StateTree{ return &StateTree{
root: hamt.NewNode(cst, hamt.UseTreeBitWidth(5)), root: adt.MakeEmptyMap(adt.WrapStore(context.TODO(), cst)),
Store: cst, Store: cst,
snaps: newStateSnaps(), snaps: newStateSnaps(),
}, nil }, nil
} }
func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) { func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
nd, err := hamt.LoadNode(context.Background(), cst, c, hamt.UseTreeBitWidth(5)) nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), c)
if err != nil { if err != nil {
log.Errorf("loading hamt node %s failed: %s", c, err) log.Errorf("loading hamt node %s failed: %s", c, err)
return nil, err return nil, err
@ -206,12 +206,10 @@ func (st *StateTree) GetActor(addr address.Address) (*types.Actor, error) {
} }
var act types.Actor var act types.Actor
err = st.root.Find(context.TODO(), string(addr.Bytes()), &act) if found, err := st.root.Get(adt.AddrKey(addr), &act); err != nil {
if err != nil {
if err == hamt.ErrNotFound {
return nil, types.ErrActorNotFound
}
return nil, xerrors.Errorf("hamt find failed: %w", err) return nil, xerrors.Errorf("hamt find failed: %w", err)
} else if !found {
return nil, types.ErrActorNotFound
} }
st.snaps.setActor(addr, &act) st.snaps.setActor(addr, &act)
@ -253,21 +251,17 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
for addr, sto := range st.snaps.layers[0].actors { for addr, sto := range st.snaps.layers[0].actors {
if sto.Delete { if sto.Delete {
if err := st.root.Delete(ctx, string(addr.Bytes())); err != nil { if err := st.root.Delete(adt.AddrKey(addr)); err != nil {
return cid.Undef, err return cid.Undef, err
} }
} else { } else {
if err := st.root.Set(ctx, string(addr.Bytes()), &sto.Act); err != nil { if err := st.root.Put(adt.AddrKey(addr), &sto.Act); err != nil {
return cid.Undef, err return cid.Undef, err
} }
} }
} }
if err := st.root.Flush(ctx); err != nil { return st.root.Root()
return cid.Undef, err
}
return st.Store.Put(ctx, st.root)
} }
func (st *StateTree) Snapshot(ctx context.Context) error { func (st *StateTree) Snapshot(ctx context.Context) error {

View File

@ -6,7 +6,6 @@ import (
"sync" "sync"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
amt "github.com/filecoin-project/go-amt-ipld/v2"
"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/actors" "github.com/filecoin-project/lotus/chain/actors"
@ -25,7 +24,6 @@ import (
bls "github.com/filecoin-project/filecoin-ffi" bls "github.com/filecoin-project/filecoin-ffi"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
blockstore "github.com/ipfs/go-ipfs-blockstore" blockstore "github.com/ipfs/go-ipfs-blockstore"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
@ -253,8 +251,13 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
return cid.Undef, cid.Undef, xerrors.Errorf("CheckProofSubmissions exit was non-zero: %d", ret.ExitCode) return cid.Undef, cid.Undef, xerrors.Errorf("CheckProofSubmissions exit was non-zero: %d", ret.ExitCode)
} }
bs := cbor.NewCborStore(sm.cs.Blockstore()) rectarr := adt.MakeEmptyArray(sm.cs.Store(ctx))
rectroot, err := amt.FromArray(ctx, bs, receipts) for i, receipt := range receipts {
if err := rectarr.Set(uint64(i), receipt); err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err)
}
}
rectroot, err := rectarr.Root()
if err != nil { if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err) return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err)
} }
@ -651,14 +654,13 @@ func (sm *StateManager) ListAllActors(ctx context.Context, ts *types.TipSet) ([]
return nil, err return nil, err
} }
cst := cbor.NewCborStore(sm.cs.Blockstore()) r, err := adt.AsMap(sm.cs.Store(ctx), st)
r, err := hamt.LoadNode(ctx, cst, st, hamt.UseTreeBitWidth(5))
if err != nil { if err != nil {
return nil, err return nil, err
} }
var out []address.Address var out []address.Address
err = r.ForEach(ctx, func(k string, val interface{}) error { err = r.ForEach(nil, func(k string) error {
addr, err := address.NewFromBytes([]byte(k)) addr, err := address.NewFromBytes([]byte(k))
if err != nil { if err != nil {
return xerrors.Errorf("address in state tree was not valid: %w", err) return xerrors.Errorf("address in state tree was not valid: %w", err)

View File

@ -13,7 +13,6 @@ import (
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
amt "github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/sector-storage/ffiwrapper" "github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
@ -258,7 +257,7 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
return nil, xerrors.Errorf("failed to enumerate all sector IDs: %w", err) return nil, xerrors.Errorf("failed to enumerate all sector IDs: %w", err)
} }
sectorAmt, err := amt.LoadAMT(ctx, sm.cs.Store(ctx), mas.Sectors) sectorAmt, err := adt.AsArray(sm.cs.Store(ctx), mas.Sectors)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to load sectors amt: %w", err) return nil, xerrors.Errorf("failed to load sectors amt: %w", err)
} }
@ -268,8 +267,10 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
sid := sectors[n] sid := sectors[n]
var sinfo miner.SectorOnChainInfo var sinfo miner.SectorOnChainInfo
if err := sectorAmt.Get(ctx, sid, &sinfo); err != nil { if found, err := sectorAmt.Get(sid, &sinfo); err != nil {
return nil, xerrors.Errorf("failed to get sector %d: %w", sid, err) return nil, xerrors.Errorf("failed to get sector %d: %w", sid, err)
} else if !found {
return nil, xerrors.Errorf("failed to find sector %d", sid)
} }
out[i] = abi.SectorInfo{ out[i] = abi.SectorInfo{
@ -328,18 +329,21 @@ func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts
if _, err := sm.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil { if _, err := sm.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil {
return nil, err return nil, err
} }
store := sm.ChainStore().Store(ctx)
da, err := amt.LoadAMT(ctx, cbor.NewCborStore(sm.ChainStore().Blockstore()), state.Proposals) da, err := adt.AsArray(store, state.Proposals)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var dp market.DealProposal var dp market.DealProposal
if err := da.Get(ctx, uint64(dealID), &dp); err != nil { if found, err := da.Get(uint64(dealID), &dp); err != nil {
return nil, err return nil, err
} else if !found {
return nil, xerrors.Errorf("deal %d not found", dealID)
} }
sa, err := market.AsDealStateArray(sm.ChainStore().Store(ctx), state.States) sa, err := market.AsDealStateArray(store, state.States)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -391,15 +395,16 @@ func ListMinerActors(ctx context.Context, sm *StateManager, ts *types.TipSet) ([
} }
func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid, filter *abi.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) { func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid, filter *abi.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) {
a, err := amt.LoadAMT(ctx, cbor.NewCborStore(bs), ssc) a, err := adt.AsArray(store.ActorStore(ctx, bs), ssc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var sset []*api.ChainSectorInfo var sset []*api.ChainSectorInfo
if err := a.ForEach(ctx, func(i uint64, v *cbg.Deferred) error { var v cbg.Deferred
if err := a.ForEach(&v, func(i int64) error {
if filter != nil { if filter != nil {
set, err := filter.IsSet(i) set, err := filter.IsSet(uint64(i))
if err != nil { if err != nil {
return xerrors.Errorf("filter check error: %w", err) return xerrors.Errorf("filter check error: %w", err)
} }

View File

@ -9,8 +9,6 @@ import (
"os" "os"
"sync" "sync"
"github.com/filecoin-project/lotus/lib/adtutil"
"github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/minio/blake2b-simd" "github.com/minio/blake2b-simd"
@ -27,8 +25,6 @@ import (
"go.opencensus.io/trace" "go.opencensus.io/trace"
"go.uber.org/multierr" "go.uber.org/multierr"
amt "github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
@ -687,20 +683,25 @@ func (cs *ChainStore) GetSignedMessage(c cid.Cid) (*types.SignedMessage, error)
func (cs *ChainStore) readAMTCids(root cid.Cid) ([]cid.Cid, error) { func (cs *ChainStore) readAMTCids(root cid.Cid) ([]cid.Cid, error) {
ctx := context.TODO() ctx := context.TODO()
bs := cbor.NewCborStore(cs.bs) a, err := adt.AsArray(cs.Store(ctx), root)
a, err := amt.LoadAMT(ctx, bs, root)
if err != nil { if err != nil {
return nil, xerrors.Errorf("amt load: %w", err) return nil, xerrors.Errorf("amt load: %w", err)
} }
var cids []cid.Cid var (
for i := uint64(0); i < a.Count; i++ { cids []cid.Cid
var c cbg.CborCid cborCid cbg.CborCid
if err := a.Get(ctx, i, &c); err != nil { )
return nil, xerrors.Errorf("failed to load cid from amt: %w", err) if err := a.ForEach(&cborCid, func(i int64) error {
c := cid.Cid(cborCid)
cids = append(cids, c)
return nil
}); err != nil {
return nil, xerrors.Errorf("failed to traverse amt: %w", err)
} }
cids = append(cids, cid.Cid(c)) if uint64(len(cids)) != a.Length() {
return nil, xerrors.Errorf("found %d cids, expected %d", len(cids), a.Length())
} }
return cids, nil return cids, nil
@ -848,15 +849,16 @@ func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message,
func (cs *ChainStore) GetParentReceipt(b *types.BlockHeader, i int) (*types.MessageReceipt, error) { func (cs *ChainStore) GetParentReceipt(b *types.BlockHeader, i int) (*types.MessageReceipt, error) {
ctx := context.TODO() ctx := context.TODO()
bs := cbor.NewCborStore(cs.bs) a, err := adt.AsArray(cs.Store(ctx), b.ParentMessageReceipts)
a, err := amt.LoadAMT(ctx, bs, b.ParentMessageReceipts)
if err != nil { if err != nil {
return nil, xerrors.Errorf("amt load: %w", err) return nil, xerrors.Errorf("amt load: %w", err)
} }
var r types.MessageReceipt var r types.MessageReceipt
if err := a.Get(ctx, uint64(i), &r); err != nil { if found, err := a.Get(uint64(i), &r); err != nil {
return nil, err return nil, err
} else if !found {
return nil, xerrors.Errorf("failed to find receipt %d", i)
} }
return &r, nil return &r, nil
@ -895,7 +897,7 @@ func (cs *ChainStore) Blockstore() bstore.Blockstore {
} }
func ActorStore(ctx context.Context, bs blockstore.Blockstore) adt.Store { func ActorStore(ctx context.Context, bs blockstore.Blockstore) adt.Store {
return adtutil.NewStore(ctx, cbor.NewCborStore(bs)) return adt.WrapStore(ctx, cbor.NewCborStore(bs))
} }
func (cs *ChainStore) Store(ctx context.Context) adt.Store { func (cs *ChainStore) Store(ctx context.Context) adt.Store {

View File

@ -4,15 +4,14 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/filecoin-project/lotus/lib/adtutil"
"sync" "sync"
"time" "time"
"golang.org/x/xerrors" "golang.org/x/xerrors"
address "github.com/filecoin-project/go-address" address "github.com/filecoin-project/go-address"
amt "github.com/filecoin-project/go-amt-ipld/v2"
miner "github.com/filecoin-project/specs-actors/actors/builtin/miner" miner "github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/util/adt"
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
dstore "github.com/ipfs/go-datastore" dstore "github.com/ipfs/go-datastore"
@ -239,31 +238,36 @@ func (bv *BlockValidator) isChainNearSynced() bool {
} }
func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error { func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error {
var bcids, scids []cbg.CBORMarshaler
for _, m := range msg.BlsMessages {
c := cbg.CborCid(m)
bcids = append(bcids, &c)
}
for _, m := range msg.SecpkMessages {
c := cbg.CborCid(m)
scids = append(scids, &c)
}
// TODO there has to be a simpler way to do this without the blockstore dance // TODO there has to be a simpler way to do this without the blockstore dance
bs := cbor.NewCborStore(bstore.NewBlockstore(dstore.NewMapDatastore())) store := adt.WrapStore(ctx, cbor.NewCborStore(bstore.NewBlockstore(dstore.NewMapDatastore())))
bmArr := adt.MakeEmptyArray(store)
smArr := adt.MakeEmptyArray(store)
bmroot, err := amt.FromArray(ctx, bs, bcids) for i, m := range msg.BlsMessages {
c := cbg.CborCid(m)
if err := bmArr.Set(uint64(i), &c); err != nil {
return err
}
}
for i, m := range msg.SecpkMessages {
c := cbg.CborCid(m)
if err := smArr.Set(uint64(i), &c); err != nil {
return err
}
}
bmroot, err := bmArr.Root()
if err != nil { if err != nil {
return err return err
} }
smroot, err := amt.FromArray(ctx, bs, scids) smroot, err := smArr.Root()
if err != nil { if err != nil {
return err return err
} }
mrcid, err := bs.Put(ctx, &types.MsgMeta{ mrcid, err := store.Put(store.Context(), &types.MsgMeta{
BlsMessages: bmroot, BlsMessages: bmroot,
SecpkMessages: smroot, SecpkMessages: smroot,
}) })
@ -318,7 +322,7 @@ func (bv *BlockValidator) getMinerWorkerKey(ctx context.Context, msg *types.Bloc
return address.Undef, err return address.Undef, err
} }
info, err := mst.GetInfo(adtutil.NewStore(ctx, cst)) info, err := mst.GetInfo(adt.WrapStore(ctx, cst))
if err != nil { if err != nil {
return address.Undef, err return address.Undef, err
} }

View File

@ -27,7 +27,6 @@ import (
bls "github.com/filecoin-project/filecoin-ffi" bls "github.com/filecoin-project/filecoin-ffi"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
amt "github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/sector-storage/ffiwrapper" "github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
@ -256,15 +255,13 @@ func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
} }
// Collect the CIDs of both types of messages separately: BLS and Secpk. // Collect the CIDs of both types of messages separately: BLS and Secpk.
var bcids, scids []cbg.CBORMarshaler var bcids, scids []cid.Cid
for _, m := range fblk.BlsMessages { for _, m := range fblk.BlsMessages {
c := cbg.CborCid(m.Cid()) bcids = append(bcids, m.Cid())
bcids = append(bcids, &c)
} }
for _, m := range fblk.SecpkMessages { for _, m := range fblk.SecpkMessages {
c := cbg.CborCid(m.Cid()) scids = append(scids, m.Cid())
scids = append(scids, &c)
} }
// TODO: IMPORTANT(GARBAGE). These message puts and the msgmeta // TODO: IMPORTANT(GARBAGE). These message puts and the msgmeta
@ -354,19 +351,17 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types
} }
var smsgs []*types.SignedMessage var smsgs []*types.SignedMessage
var smsgCids []cbg.CBORMarshaler var smsgCids []cid.Cid
for _, m := range smi[bi] { for _, m := range smi[bi] {
smsgs = append(smsgs, allsmsgs[m]) smsgs = append(smsgs, allsmsgs[m])
c := cbg.CborCid(allsmsgs[m].Cid()) smsgCids = append(smsgCids, allsmsgs[m].Cid())
smsgCids = append(smsgCids, &c)
} }
var bmsgs []*types.Message var bmsgs []*types.Message
var bmsgCids []cbg.CBORMarshaler var bmsgCids []cid.Cid
for _, m := range bmi[bi] { for _, m := range bmi[bi] {
bmsgs = append(bmsgs, allbmsgs[m]) bmsgs = append(bmsgs, allbmsgs[m])
c := cbg.CborCid(allbmsgs[m].Cid()) bmsgCids = append(bmsgCids, allbmsgs[m].Cid())
bmsgCids = append(bmsgCids, &c)
} }
mrcid, err := computeMsgMeta(bs, bmsgCids, smsgCids) mrcid, err := computeMsgMeta(bs, bmsgCids, smsgCids)
@ -392,19 +387,36 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types
// computeMsgMeta computes the root CID of the combined arrays of message CIDs // computeMsgMeta computes the root CID of the combined arrays of message CIDs
// of both types (BLS and Secpk). // of both types (BLS and Secpk).
func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cbg.CBORMarshaler) (cid.Cid, error) { func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cid.Cid) (cid.Cid, error) {
ctx := context.TODO() store := adt.WrapStore(context.TODO(), bs)
bmroot, err := amt.FromArray(ctx, bs, bmsgCids) bmArr := adt.MakeEmptyArray(store)
smArr := adt.MakeEmptyArray(store)
for i, m := range bmsgCids {
c := cbg.CborCid(m)
if err := bmArr.Set(uint64(i), &c); err != nil {
return cid.Undef, err
}
}
for i, m := range smsgCids {
c := cbg.CborCid(m)
if err := smArr.Set(uint64(i), &c); err != nil {
return cid.Undef, err
}
}
bmroot, err := bmArr.Root()
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, err
} }
smroot, err := amt.FromArray(ctx, bs, smsgCids) smroot, err := smArr.Root()
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, err
} }
mrcid, err := bs.Put(ctx, &types.MsgMeta{ mrcid, err := store.Put(store.Context(), &types.MsgMeta{
BlsMessages: bmroot, BlsMessages: bmroot,
SecpkMessages: smroot, SecpkMessages: smroot,
}) })
@ -993,18 +1005,21 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
return nil return nil
} }
var blsCids []cbg.CBORMarshaler store := adt.WrapStore(ctx, cst)
bmArr := adt.MakeEmptyArray(store)
for i, m := range b.BlsMessages { for i, m := range b.BlsMessages {
if err := checkMsg(m); err != nil { if err := checkMsg(m); err != nil {
return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err) return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
} }
c := cbg.CborCid(m.Cid()) c := cbg.CborCid(m.Cid())
blsCids = append(blsCids, &c) if err := bmArr.Set(uint64(i), &c); err != nil {
return xerrors.Errorf("failed to put bls message at index %d: %w", i, err)
}
} }
var secpkCids []cbg.CBORMarshaler smArr := adt.MakeEmptyArray(store)
for i, m := range b.SecpkMessages { for i, m := range b.SecpkMessages {
if err := checkMsg(m); err != nil { if err := checkMsg(m); err != nil {
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err) return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
@ -1022,17 +1037,19 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
} }
c := cbg.CborCid(m.Cid()) c := cbg.CborCid(m.Cid())
secpkCids = append(secpkCids, &c) if err := smArr.Set(uint64(i), &c); err != nil {
return xerrors.Errorf("failed to put secpk message at index %d: %w", i, err)
}
} }
bmroot, err := amt.FromArray(ctx, cst, blsCids) bmroot, err := bmArr.Root()
if err != nil { if err != nil {
return xerrors.Errorf("failed to build amt from bls msg cids: %w", err) return err
} }
smroot, err := amt.FromArray(ctx, cst, secpkCids) smroot, err := smArr.Root()
if err != nil { if err != nil {
return xerrors.Errorf("failed to build amt from bls msg cids: %w", err) return err
} }
mrcid, err := cst.Put(ctx, &types.MsgMeta{ mrcid, err := cst.Put(ctx, &types.MsgMeta{

View File

@ -20,7 +20,6 @@ import (
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
"github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
"go.opencensus.io/trace" "go.opencensus.io/trace"
@ -464,7 +463,7 @@ func (rt *Runtime) GetBalance(a address.Address) (types.BigInt, aerrors.ActorErr
switch err { switch err {
default: default:
return types.EmptyInt, aerrors.Escalate(err, "failed to look up actor balance") return types.EmptyInt, aerrors.Escalate(err, "failed to look up actor balance")
case hamt.ErrNotFound: case types.ErrActorNotFound:
return types.NewInt(0), nil return types.NewInt(0), nil
case nil: case nil:
return act.Balance, nil return act.Balance, nil

View File

@ -16,12 +16,12 @@ import (
"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"
"github.com/filecoin-project/lotus/lib/adtutil"
"github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/specs-actors/actors/runtime" "github.com/filecoin-project/specs-actors/actors/runtime"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/sector-storage/ffiwrapper" "github.com/filecoin-project/sector-storage/ffiwrapper"
) )
@ -191,7 +191,7 @@ func (ss *syscallShim) VerifyBlockSig(blk *types.BlockHeader) error {
return err return err
} }
info, err := mas.GetInfo(adtutil.NewStore(ss.ctx, ss.cst)) info, err := mas.GetInfo(adt.WrapStore(ss.ctx, ss.cst))
if err != nil { if err != nil {
return err return err
} }

View File

@ -12,15 +12,14 @@ import (
"text/tabwriter" "text/tabwriter"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig" samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
cid "github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
"github.com/ipfs/go-hamt-ipld"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
@ -237,24 +236,20 @@ var msigInspectCmd = &cli.Command{
func GetMultisigPending(ctx context.Context, lapi api.FullNode, hroot cid.Cid) (map[int64]*samsig.Transaction, error) { func GetMultisigPending(ctx context.Context, lapi api.FullNode, hroot cid.Cid) (map[int64]*samsig.Transaction, error) {
bs := apibstore.NewAPIBlockstore(lapi) bs := apibstore.NewAPIBlockstore(lapi)
cst := cbor.NewCborStore(bs) store := adt.WrapStore(ctx, cbor.NewCborStore(bs))
nd, err := hamt.LoadNode(ctx, cst, hroot, hamt.UseTreeBitWidth(5)) nd, err := adt.AsMap(store, hroot)
if err != nil { if err != nil {
return nil, err return nil, err
} }
txs := make(map[int64]*samsig.Transaction) txs := make(map[int64]*samsig.Transaction)
err = nd.ForEach(ctx, func(k string, val interface{}) error {
d := val.(*cbg.Deferred)
var tx samsig.Transaction var tx samsig.Transaction
if err := tx.UnmarshalCBOR(bytes.NewReader(d.Raw)); err != nil { err = nd.ForEach(&tx, func(k string) error {
return err
}
txid, _ := binary.Varint([]byte(k)) txid, _ := binary.Varint([]byte(k))
txs[txid] = &tx cpy := tx // copy so we don't clobber on future iterations.
txs[txid] = &cpy
return nil return nil
}) })
if err != nil { if err != nil {

View File

@ -1,7 +1,6 @@
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
@ -16,10 +15,8 @@ import (
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
"github.com/ipfs/go-hamt-ipld" "github.com/filecoin-project/specs-actors/actors/util/adt"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
cbg "github.com/whyrusleeping/cbor-gen"
) )
var verifRegCmd = &cli.Command{ var verifRegCmd = &cli.Command{
@ -193,27 +190,22 @@ var verifRegListVerifiersCmd = &cli.Command{
} }
apibs := apibstore.NewAPIBlockstore(api) apibs := apibstore.NewAPIBlockstore(api)
cst := cbor.NewCborStore(apibs) store := adt.WrapStore(ctx, cbor.NewCborStore(apibs))
var st verifreg.State var st verifreg.State
if err := cst.Get(ctx, act.Head, &st); err != nil { if err := store.Get(ctx, act.Head, &st); err != nil {
return err return err
} }
vh, err := hamt.LoadNode(ctx, cst, st.Verifiers, hamt.UseTreeBitWidth(5)) vh, err := adt.AsMap(store, st.Verifiers)
if err != nil {
return err
}
if err := vh.ForEach(ctx, func(k string, val interface{}) error {
addr, err := address.NewFromBytes([]byte(k))
if err != nil { if err != nil {
return err return err
} }
var dcap verifreg.DataCap var dcap verifreg.DataCap
if err := vh.ForEach(&dcap, func(k string) error {
if err := dcap.UnmarshalCBOR(bytes.NewReader(val.(*cbg.Deferred).Raw)); err != nil { addr, err := address.NewFromBytes([]byte(k))
if err != nil {
return err return err
} }
@ -245,27 +237,22 @@ var verifRegListClientsCmd = &cli.Command{
} }
apibs := apibstore.NewAPIBlockstore(api) apibs := apibstore.NewAPIBlockstore(api)
cst := cbor.NewCborStore(apibs) store := adt.WrapStore(ctx, cbor.NewCborStore(apibs))
var st verifreg.State var st verifreg.State
if err := cst.Get(ctx, act.Head, &st); err != nil { if err := store.Get(ctx, act.Head, &st); err != nil {
return err return err
} }
vh, err := hamt.LoadNode(ctx, cst, st.VerifiedClients, hamt.UseTreeBitWidth(5)) vh, err := adt.AsMap(store, st.VerifiedClients)
if err != nil {
return err
}
if err := vh.ForEach(ctx, func(k string, val interface{}) error {
addr, err := address.NewFromBytes([]byte(k))
if err != nil { if err != nil {
return err return err
} }
var dcap verifreg.DataCap var dcap verifreg.DataCap
if err := vh.ForEach(&dcap, func(k string) error {
if err := dcap.UnmarshalCBOR(bytes.NewReader(val.(*cbg.Deferred).Raw)); err != nil { addr, err := address.NewFromBytes([]byte(k))
if err != nil {
return err return err
} }
@ -340,21 +327,23 @@ var verifRegCheckVerifierCmd = &cli.Command{
} }
apibs := apibstore.NewAPIBlockstore(api) apibs := apibstore.NewAPIBlockstore(api)
cst := cbor.NewCborStore(apibs) store := adt.WrapStore(ctx, cbor.NewCborStore(apibs))
var st verifreg.State var st verifreg.State
if err := cst.Get(ctx, act.Head, &st); err != nil { if err := store.Get(ctx, act.Head, &st); err != nil {
return err return err
} }
vh, err := hamt.LoadNode(ctx, cst, st.Verifiers, hamt.UseTreeBitWidth(5)) vh, err := adt.AsMap(store, st.Verifiers)
if err != nil { if err != nil {
return err return err
} }
var dcap verifreg.DataCap var dcap verifreg.DataCap
if err := vh.Find(ctx, string(vaddr.Bytes()), &dcap); err != nil { if found, err := vh.Get(adt.AddrKey(vaddr), &dcap); err != nil {
return err return err
} else if !found {
return fmt.Errorf("not found")
} }
fmt.Println(dcap) fmt.Println(dcap)

3
go.mod
View File

@ -18,7 +18,6 @@ require (
github.com/filecoin-project/chain-validation v0.0.6-0.20200720093255-843129967fdf github.com/filecoin-project/chain-validation v0.0.6-0.20200720093255-843129967fdf
github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200716204036-cddc56607e1d github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200716204036-cddc56607e1d
github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef
github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2
github.com/filecoin-project/go-bitfield v0.0.4-0.20200703174658-f4a5758051a1 github.com/filecoin-project/go-bitfield v0.0.4-0.20200703174658-f4a5758051a1
github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03
@ -54,7 +53,7 @@ require (
github.com/ipfs/go-filestore v1.0.0 github.com/ipfs/go-filestore v1.0.0
github.com/ipfs/go-fs-lock v0.0.1 github.com/ipfs/go-fs-lock v0.0.1
github.com/ipfs/go-graphsync v0.0.6-0.20200715142715-e2f27c4754e6 github.com/ipfs/go-graphsync v0.0.6-0.20200715142715-e2f27c4754e6
github.com/ipfs/go-hamt-ipld v0.1.1-0.20200605182717-0310ad2b0b1f github.com/ipfs/go-hamt-ipld v0.1.1-0.20200605182717-0310ad2b0b1f // indirect
github.com/ipfs/go-ipfs-blockstore v1.0.0 github.com/ipfs/go-ipfs-blockstore v1.0.0
github.com/ipfs/go-ipfs-chunker v0.0.5 github.com/ipfs/go-ipfs-chunker v0.0.5
github.com/ipfs/go-ipfs-ds-help v1.0.0 github.com/ipfs/go-ipfs-ds-help v1.0.0

View File

@ -1,34 +0,0 @@
package adtutil
import (
"context"
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/filecoin-project/specs-actors/actors/util/adt"
)
func NewStore(ctx context.Context, cst cbor.IpldStore) adt.Store {
return &store{
cst: cst,
ctx: ctx,
}
}
type store struct {
cst cbor.IpldStore
ctx context.Context
}
func (a *store) Context() context.Context {
return a.ctx
}
func (a *store) Get(ctx context.Context, c cid.Cid, out interface{}) error {
return a.cst.Get(ctx, c, out)
}
func (a *store) Put(ctx context.Context, v interface{}) (cid.Cid, error) {
return a.cst.Put(ctx, v)
}

View File

@ -4,19 +4,16 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/ipfs/go-blockservice" "github.com/ipfs/go-blockservice"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/ipfs/go-hamt-ipld"
blockstore "github.com/ipfs/go-ipfs-blockstore" blockstore "github.com/ipfs/go-ipfs-blockstore"
offline "github.com/ipfs/go-ipfs-exchange-offline" offline "github.com/ipfs/go-ipfs-exchange-offline"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
@ -26,6 +23,7 @@ import (
"github.com/ipfs/go-path" "github.com/ipfs/go-path"
"github.com/ipfs/go-path/resolver" "github.com/ipfs/go-path/resolver"
mh "github.com/multiformats/go-multihash" mh "github.com/multiformats/go-multihash"
cbg "github.com/whyrusleeping/cbor-gen"
"go.uber.org/fx" "go.uber.org/fx"
"golang.org/x/xerrors" "golang.org/x/xerrors"
@ -265,8 +263,17 @@ func (a *ChainAPI) ChainTipSetWeight(ctx context.Context, tsk types.TipSetKey) (
return a.Chain.Weight(ctx, ts) return a.Chain.Weight(ctx, ts)
} }
// This allows us to lookup string keys in the actor's adt.Map type.
type stringKey string
func (s stringKey) Key() string {
return (string)(s)
}
func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) { func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) {
return func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) { return func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) {
store := adt.WrapStore(ctx, cbor.NewCborStore(bs))
if strings.HasPrefix(names[0], "@Ha:") { if strings.HasPrefix(names[0], "@Ha:") {
addr, err := address.NewFromString(names[0][4:]) addr, err := address.NewFromString(names[0][4:])
if err != nil { if err != nil {
@ -290,7 +297,7 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod
if strings.HasPrefix(names[0], "@Hu:") { if strings.HasPrefix(names[0], "@Hu:") {
i, err := strconv.ParseUint(names[0][4:], 10, 64) i, err := strconv.ParseUint(names[0][4:], 10, 64)
if err != nil { if err != nil {
return nil, nil, xerrors.Errorf("parsing int64: %w", err) return nil, nil, xerrors.Errorf("parsing uint64: %w", err)
} }
ik := adt.UIntKey(i) ik := adt.UIntKey(i)
@ -299,16 +306,20 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod
} }
if strings.HasPrefix(names[0], "@H:") { if strings.HasPrefix(names[0], "@H:") {
cst := cbor.NewCborStore(bs) h, err := adt.AsMap(store, nd.Cid())
h, err := hamt.LoadNode(ctx, cst, nd.Cid(), hamt.UseTreeBitWidth(5))
if err != nil { if err != nil {
return nil, nil, xerrors.Errorf("resolving hamt link: %w", err) return nil, nil, xerrors.Errorf("resolving hamt link: %w", err)
} }
var m interface{} var deferred cbg.Deferred
if err := h.Find(ctx, names[0][3:], &m); err != nil { if found, err := h.Get(stringKey(names[0][3:]), &deferred); err != nil {
return nil, nil, xerrors.Errorf("resolve hamt: %w", err) return nil, nil, xerrors.Errorf("resolve hamt: %w", err)
} else if !found {
return nil, nil, xerrors.Errorf("resolve hamt: not found")
}
var m interface{}
if err := cbor.DecodeInto(deferred.Raw, &m); err != nil {
return nil, nil, xerrors.Errorf("failed to decode cbor object: %w", err)
} }
if c, ok := m.(cid.Cid); ok { if c, ok := m.(cid.Cid); ok {
return &ipld.Link{ return &ipld.Link{
@ -337,7 +348,7 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod
} }
if strings.HasPrefix(names[0], "@A:") { if strings.HasPrefix(names[0], "@A:") {
a, err := amt.LoadAMT(ctx, cbor.NewCborStore(bs), nd.Cid()) a, err := adt.AsArray(store, nd.Cid())
if err != nil { if err != nil {
return nil, nil, xerrors.Errorf("load amt: %w", err) return nil, nil, xerrors.Errorf("load amt: %w", err)
} }
@ -347,11 +358,17 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod
return nil, nil, xerrors.Errorf("parsing amt index: %w", err) return nil, nil, xerrors.Errorf("parsing amt index: %w", err)
} }
var m interface{} var deferred cbg.Deferred
if err := a.Get(ctx, idx, &m); err != nil { if found, err := a.Get(idx, &deferred); err != nil {
return nil, nil, xerrors.Errorf("amt get: %w", err) return nil, nil, xerrors.Errorf("resolve amt: %w", err)
} else if !found {
return nil, nil, xerrors.Errorf("resolve amt: not found")
} }
fmt.Printf("AG %T %v\n", m, m) var m interface{}
if err := cbor.DecodeInto(deferred.Raw, &m); err != nil {
return nil, nil, xerrors.Errorf("failed to decode cbor object: %w", err)
}
if c, ok := m.(cid.Cid); ok { if c, ok := m.(cid.Cid); ok {
return &ipld.Link{ return &ipld.Link{
Name: names[0][3:], Name: names[0][3:],

View File

@ -8,14 +8,12 @@ import (
"strconv" "strconv"
cid "github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
"github.com/ipfs/go-hamt-ipld"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
"go.uber.org/fx" "go.uber.org/fx"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/sector-storage/ffiwrapper" "github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
@ -522,30 +520,27 @@ func (a *StateAPI) StateMarketParticipants(ctx context.Context, tsk types.TipSet
if _, err := a.StateManager.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil { if _, err := a.StateManager.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil {
return nil, err return nil, err
} }
cst := cbor.NewCborStore(a.StateManager.ChainStore().Blockstore()) store := a.StateManager.ChainStore().Store(ctx)
escrow, err := hamt.LoadNode(ctx, cst, state.EscrowTable, hamt.UseTreeBitWidth(5)) // todo: adt map escrow, err := adt.AsMap(store, state.EscrowTable)
if err != nil { if err != nil {
return nil, err return nil, err
} }
locked, err := hamt.LoadNode(ctx, cst, state.LockedTable, hamt.UseTreeBitWidth(5)) locked, err := adt.AsMap(store, state.LockedTable)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = escrow.ForEach(ctx, func(k string, val interface{}) error { var es, lk abi.TokenAmount
cv := val.(*cbg.Deferred) err = escrow.ForEach(&es, func(k string) error {
a, err := address.NewFromBytes([]byte(k)) a, err := address.NewFromBytes([]byte(k))
if err != nil { if err != nil {
return err return err
} }
var es abi.TokenAmount if found, err := locked.Get(adt.AddrKey(a), &lk); err != nil {
if err := es.UnmarshalCBOR(bytes.NewReader(cv.Raw)); err != nil {
return err
}
var lk abi.TokenAmount
if err := locked.Find(ctx, k, &es); err != nil {
return err return err
} else if !found {
return fmt.Errorf("locked funds not found")
} }
out[a.String()] = api.MarketBalance{ out[a.String()] = api.MarketBalance{
@ -572,29 +567,23 @@ func (a *StateAPI) StateMarketDeals(ctx context.Context, tsk types.TipSetKey) (m
return nil, err return nil, err
} }
blks := cbor.NewCborStore(a.StateManager.ChainStore().Blockstore()) store := a.StateManager.ChainStore().Store(ctx)
da, err := amt.LoadAMT(ctx, blks, state.Proposals) da, err := adt.AsArray(store, state.Proposals)
if err != nil { if err != nil {
return nil, err return nil, err
} }
sa, err := amt.LoadAMT(ctx, blks, state.States) sa, err := adt.AsArray(store, state.States)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := da.ForEach(ctx, func(i uint64, v *cbg.Deferred) error {
var d market.DealProposal var d market.DealProposal
if err := d.UnmarshalCBOR(bytes.NewReader(v.Raw)); err != nil { if err := da.ForEach(&d, func(i int64) error {
return err
}
var s market.DealState var s market.DealState
if err := sa.Get(ctx, i, &s); err != nil { if found, err := sa.Get(uint64(i), &s); err != nil {
if _, ok := err.(*amt.ErrNotFound); !ok {
return xerrors.Errorf("failed to get state for deal in proposals array: %w", err) return xerrors.Errorf("failed to get state for deal in proposals array: %w", err)
} } else if !found {
s.SectorStartEpoch = -1 s.SectorStartEpoch = -1
} }
out[strconv.FormatInt(int64(i), 10)] = api.MarketDeal{ out[strconv.FormatInt(int64(i), 10)] = api.MarketDeal{
@ -617,47 +606,51 @@ func (a *StateAPI) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID
} }
func (a *StateAPI) StateChangedActors(ctx context.Context, old cid.Cid, new cid.Cid) (map[string]types.Actor, error) { func (a *StateAPI) StateChangedActors(ctx context.Context, old cid.Cid, new cid.Cid) (map[string]types.Actor, error) {
cst := cbor.NewCborStore(a.Chain.Blockstore()) store := adt.WrapStore(ctx, cbor.NewCborStore(a.Chain.Blockstore()))
nh, err := hamt.LoadNode(ctx, cst, new, hamt.UseTreeBitWidth(5)) nh, err := adt.AsMap(store, new)
if err != nil { if err != nil {
return nil, err return nil, err
} }
oh, err := hamt.LoadNode(ctx, cst, old, hamt.UseTreeBitWidth(5)) oh, err := adt.AsMap(store, old)
if err != nil { if err != nil {
return nil, err return nil, err
} }
out := map[string]types.Actor{} out := map[string]types.Actor{}
err = nh.ForEach(ctx, func(k string, nval interface{}) error { var (
ncval := nval.(*cbg.Deferred) ncval, ocval cbg.Deferred
buf = bytes.NewReader(nil)
)
err = nh.ForEach(&ncval, func(k string) error {
var act types.Actor var act types.Actor
var ocval cbg.Deferred
switch err := oh.Find(ctx, k, &ocval); err {
case nil:
if bytes.Equal(ocval.Raw, ncval.Raw) {
return nil // not changed
}
fallthrough
case hamt.ErrNotFound:
if err := act.UnmarshalCBOR(bytes.NewReader(ncval.Raw)); err != nil {
return err
}
addr, err := address.NewFromBytes([]byte(k)) addr, err := address.NewFromBytes([]byte(k))
if err != nil { if err != nil {
return xerrors.Errorf("address in state tree was not valid: %w", err) return xerrors.Errorf("address in state tree was not valid: %w", err)
} }
out[addr.String()] = act found, err := oh.Get(adt.AddrKey(addr), &ocval)
default: if err != nil {
return err return err
} }
if found && bytes.Equal(ocval.Raw, ncval.Raw) {
return nil // not changed
}
buf.Reset(ncval.Raw)
err = act.UnmarshalCBOR(buf)
buf.Reset(nil)
if err != nil {
return err
}
out[addr.String()] = act
return nil return nil
}) })
if err != nil { if err != nil {
@ -1039,24 +1032,23 @@ func (a *StateAPI) StateVerifiedClientStatus(ctx context.Context, addr address.A
return nil, err return nil, err
} }
cst := cbor.NewCborStore(a.StateManager.ChainStore().Blockstore()) store := a.StateManager.ChainStore().Store(ctx)
var st verifreg.State var st verifreg.State
if err := cst.Get(ctx, act.Head, &st); err != nil { if err := store.Get(ctx, act.Head, &st); err != nil {
return nil, err return nil, err
} }
vh, err := hamt.LoadNode(ctx, cst, st.VerifiedClients, hamt.UseTreeBitWidth(5)) vh, err := adt.AsMap(store, st.VerifiedClients)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var dcap verifreg.DataCap var dcap verifreg.DataCap
if err := vh.Find(ctx, string(addr.Bytes()), &dcap); err != nil { if found, err := vh.Get(adt.AddrKey(addr), &dcap); err != nil {
if err == hamt.ErrNotFound {
return nil, nil
}
return nil, err return nil, err
} else if !found {
return nil, nil
} }
return &dcap, nil return &dcap, nil