Skip to content

Commit

Permalink
feat(market): update state diffing for market actor
Browse files Browse the repository at this point in the history
Update to abstract actor for markets state diffing. Also move the diff adt functions inside the
abstract actors
  • Loading branch information
hannahhoward committed Sep 17, 2020
1 parent 7115485 commit 80b6994
Show file tree
Hide file tree
Showing 7 changed files with 373 additions and 215 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package state
package adt

import (
"bytes"

"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/specs-actors/actors/util/adt"
typegen "github.com/whyrusleeping/cbor-gen"
)

Expand All @@ -27,7 +26,7 @@ type AdtArrayDiff interface {
// - All values that exist in curArr nnd not in prevArr are passed to adtArrayDiff.Add()
// - All values that exist in preArr and in curArr are passed to AdtArrayDiff.Modify()
// - It is the responsibility of AdtArrayDiff.Modify() to determine if the values it was passed have been modified.
func DiffAdtArray(preArr, curArr *adt.Array, out AdtArrayDiff) error {
func DiffAdtArray(preArr, curArr Array, out AdtArrayDiff) error {
prevVal := new(typegen.Deferred)
if err := preArr.ForEach(prevVal, func(i int64) error {
curVal := new(typegen.Deferred)
Expand Down Expand Up @@ -76,7 +75,7 @@ type AdtMapDiff interface {
Remove(key string, val *typegen.Deferred) error
}

func DiffAdtMap(preMap, curMap *adt.Map, out AdtMapDiff) error {
func DiffAdtMap(preMap, curMap Map, out AdtMapDiff) error {
prevVal := new(typegen.Deferred)
if err := preMap.ForEach(prevVal, func(key string) error {
curVal := new(typegen.Deferred)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package state
package adt

import (
"bytes"
Expand All @@ -13,7 +13,7 @@ import (

"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/specs-actors/actors/runtime"
"github.com/filecoin-project/specs-actors/actors/util/adt"
v0adt "github.com/filecoin-project/specs-actors/actors/util/adt"

bstore "github.com/filecoin-project/lotus/lib/blockstore"
)
Expand All @@ -22,8 +22,8 @@ func TestDiffAdtArray(t *testing.T) {
ctxstoreA := newContextStore()
ctxstoreB := newContextStore()

arrA := adt.MakeEmptyArray(ctxstoreA)
arrB := adt.MakeEmptyArray(ctxstoreB)
arrA := v0adt.MakeEmptyArray(ctxstoreA)
arrB := v0adt.MakeEmptyArray(ctxstoreB)

require.NoError(t, arrA.Set(0, runtime.CBORBytes([]byte{0}))) // delete

Expand Down Expand Up @@ -76,8 +76,8 @@ func TestDiffAdtMap(t *testing.T) {
ctxstoreA := newContextStore()
ctxstoreB := newContextStore()

mapA := adt.MakeEmptyMap(ctxstoreA)
mapB := adt.MakeEmptyMap(ctxstoreB)
mapA := v0adt.MakeEmptyMap(ctxstoreA)
mapB := v0adt.MakeEmptyMap(ctxstoreB)

require.NoError(t, mapA.Put(abi.UIntKey(0), runtime.CBORBytes([]byte{0}))) // delete

Expand Down Expand Up @@ -292,12 +292,9 @@ func (t *TestDiffArray) Remove(key uint64, val *typegen.Deferred) error {
return nil
}

func newContextStore() *contextStore {
func newContextStore() Store {
ctx := context.Background()
bs := bstore.NewTemporarySync()
store := cbornode.NewCborStore(bs)
return &contextStore{
ctx: ctx,
cst: store,
}
return WrapStore(ctx, store)
}
52 changes: 52 additions & 0 deletions chain/actors/builtin/market/market.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,14 @@ func Load(store adt.Store, act *types.Actor) (st State, err error) {

type State interface {
cbor.Marshaler
BalancesChanged(State) bool
EscrowTable() (BalanceTable, error)
LockedTable() (BalanceTable, error)
TotalLocked() (abi.TokenAmount, error)
StatesChanged(State) bool
States() (DealStates, error)
ProposalsChanged(State) bool
Proposals() (DealProposals, error)
VerifyDealsForActivation(
minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch,
) (weight, verifiedWeight abi.DealWeight, err error)
Expand All @@ -40,3 +45,50 @@ type State interface {
type BalanceTable interface {
Get(key address.Address) (abi.TokenAmount, error)
}

type DealStates interface {
GetDeal(key abi.DealID) (DealState, error)
Diff(DealStates) (*DealStateChanges, error)
}

type DealProposals interface {
Diff(DealProposals) (*DealProposalChanges, error)
}

type DealState interface {
SectorStartEpoch() abi.ChainEpoch
SlashEpoch() abi.ChainEpoch
LastUpdatedEpoch() abi.ChainEpoch
Equals(DealState) bool
}

type DealProposal interface {
}

type DealStateChanges struct {
Added []DealIDState
Modified []DealStateChange
Removed []DealIDState
}

type DealIDState struct {
ID abi.DealID
Deal DealState
}

// DealStateChange is a change in deal state from -> to
type DealStateChange struct {
ID abi.DealID
From DealState
To DealState
}

type DealProposalChanges struct {
Added []ProposalIDState
Removed []ProposalIDState
}

type ProposalIDState struct {
ID abi.DealID
Proposal DealProposal
}
201 changes: 198 additions & 3 deletions chain/actors/builtin/market/v0.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package market

import (
"bytes"
"errors"
"fmt"

"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
"github.com/filecoin-project/specs-actors/actors/util/adt"
v0adt "github.com/filecoin-project/specs-actors/actors/util/adt"
typegen "github.com/whyrusleeping/cbor-gen"
)

type v0State struct {
Expand All @@ -19,16 +25,205 @@ func (s *v0State) TotalLocked() (abi.TokenAmount, error) {
return fml, nil
}

func (s *v0State) BalancesChanged(otherState State) bool {
v0otherState, ok := otherState.(*v0State)
if !ok {
// there's no way to compare differnt versions of the state, so let's
// just say that means the state of balances has changed
return true
}
return !s.State.EscrowTable.Equals(v0otherState.State.EscrowTable) || !s.State.LockedTable.Equals(v0otherState.State.LockedTable)
}

func (s *v0State) StatesChanged(otherState State) bool {
v0otherState, ok := otherState.(*v0State)
if !ok {
// there's no way to compare differnt versions of the state, so let's
// just say that means the state of balances has changed
return true
}
return !s.State.States.Equals(v0otherState.State.States)
}

func (s *v0State) States() (DealStates, error) {
stateArray, err := v0adt.AsArray(s.store, s.State.States)
if err != nil {
return nil, err
}
return &v0DealStates{stateArray}, nil
}

func (s *v0State) ProposalsChanged(otherState State) bool {
v0otherState, ok := otherState.(*v0State)
if !ok {
// there's no way to compare differnt versions of the state, so let's
// just say that means the state of balances has changed
return true
}
return !s.State.Proposals.Equals(v0otherState.State.Proposals)
}

func (s *v0State) Proposals() (DealProposals, error) {
proposalArray, err := v0adt.AsArray(s.store, s.State.Proposals)
if err != nil {
return nil, err
}
return &v0DealProposals{proposalArray}, nil
}

func (s *v0State) EscrowTable() (BalanceTable, error) {
return adt.AsBalanceTable(s.store, s.State.EscrowTable)
return v0adt.AsBalanceTable(s.store, s.State.EscrowTable)
}

func (s *v0State) LockedTable() (BalanceTable, error) {
return adt.AsBalanceTable(s.store, s.State.LockedTable)
return v0adt.AsBalanceTable(s.store, s.State.LockedTable)
}

func (s *v0State) VerifyDealsForActivation(
minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch,
) (weight, verifiedWeight abi.DealWeight, err error) {
return market.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch)
}

type v0DealStates struct {
adt.Array
}

func (s *v0DealStates) GetDeal(dealID abi.DealID) (DealState, error) {
var deal market.DealState
found, err := s.Array.Get(uint64(dealID), &deal)
if err != nil {
return nil, err
}
if !found {
return nil, nil
}
return &v0DealState{deal}, nil
}

func (s *v0DealStates) Diff(other DealStates) (*DealStateChanges, error) {
v0other, ok := other.(*v0DealStates)
if !ok {
// TODO handle this if possible on a case by case basis but for now, just fail
return nil, errors.New("cannot compare deal states across versions")
}
results := new(DealStateChanges)
if err := adt.DiffAdtArray(s, v0other, &v0MarketStatesDiffer{results}); err != nil {
return nil, fmt.Errorf("diffing deal states: %w", err)
}

return results, nil
}

type v0MarketStatesDiffer struct {
Results *DealStateChanges
}

func (d *v0MarketStatesDiffer) Add(key uint64, val *typegen.Deferred) error {
ds := new(v0DealState)
err := ds.UnmarshalCBOR(bytes.NewReader(val.Raw))
if err != nil {
return err
}
d.Results.Added = append(d.Results.Added, DealIDState{abi.DealID(key), ds})
return nil
}

func (d *v0MarketStatesDiffer) Modify(key uint64, from, to *typegen.Deferred) error {
dsFrom := new(v0DealState)
if err := dsFrom.UnmarshalCBOR(bytes.NewReader(from.Raw)); err != nil {
return err
}

dsTo := new(v0DealState)
if err := dsTo.UnmarshalCBOR(bytes.NewReader(to.Raw)); err != nil {
return err
}

if *dsFrom != *dsTo {
d.Results.Modified = append(d.Results.Modified, DealStateChange{abi.DealID(key), dsFrom, dsTo})
}
return nil
}

func (d *v0MarketStatesDiffer) Remove(key uint64, val *typegen.Deferred) error {
ds := new(v0DealState)
err := ds.UnmarshalCBOR(bytes.NewReader(val.Raw))
if err != nil {
return err
}
d.Results.Removed = append(d.Results.Removed, DealIDState{abi.DealID(key), ds})
return nil
}

type v0DealState struct {
market.DealState
}

func (ds *v0DealState) SectorStartEpoch() abi.ChainEpoch {
return ds.DealState.SectorStartEpoch
}

func (ds *v0DealState) SlashEpoch() abi.ChainEpoch {
return ds.DealState.SlashEpoch
}

func (ds *v0DealState) LastUpdatedEpoch() abi.ChainEpoch {
return ds.DealState.LastUpdatedEpoch
}

func (ds *v0DealState) Equals(other DealState) bool {
v0other, ok := other.(*v0DealState)
return ok && *ds == *v0other
}

type v0DealProposals struct {
adt.Array
}

func (s *v0DealProposals) Diff(other DealProposals) (*DealProposalChanges, error) {
v0other, ok := other.(*v0DealProposals)
if !ok {
// TODO handle this if possible on a case by case basis but for now, just fail
return nil, errors.New("cannot compare deal proposals across versions")
}
results := new(DealProposalChanges)
if err := adt.DiffAdtArray(s, v0other, &v0MarketProposalsDiffer{results}); err != nil {
return nil, fmt.Errorf("diffing deal proposals: %w", err)
}

return results, nil
}

type v0MarketProposalsDiffer struct {
Results *DealProposalChanges
}

type v0DealProposal struct {
market.DealProposal
}

func (d *v0MarketProposalsDiffer) Add(key uint64, val *typegen.Deferred) error {
dp := new(v0DealProposal)
err := dp.UnmarshalCBOR(bytes.NewReader(val.Raw))
if err != nil {
return err
}
d.Results.Added = append(d.Results.Added, ProposalIDState{abi.DealID(key), dp})
return nil
}

func (d *v0MarketProposalsDiffer) Modify(key uint64, from, to *typegen.Deferred) error {
// short circuit, DealProposals are static
return nil
}

func (d *v0MarketProposalsDiffer) Remove(key uint64, val *typegen.Deferred) error {
dp := new(v0DealProposal)
err := dp.UnmarshalCBOR(bytes.NewReader(val.Raw))
if err != nil {
return err
}
d.Results.Removed = append(d.Results.Removed, ProposalIDState{abi.DealID(key), dp})
return nil
}
Loading

0 comments on commit 80b6994

Please sign in to comment.