Merge pull request #415 from filecoin-project/feat/deals-on-chain
On-Chain deals
This commit is contained in:
commit
eeca3d86df
12
api/api.go
12
api/api.go
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
|
||||||
"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/address"
|
"github.com/filecoin-project/lotus/chain/address"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -132,6 +133,9 @@ type FullNode interface {
|
|||||||
StateWaitMsg(context.Context, cid.Cid) (*MsgWait, error)
|
StateWaitMsg(context.Context, cid.Cid) (*MsgWait, error)
|
||||||
StateListMiners(context.Context, *types.TipSet) ([]address.Address, error)
|
StateListMiners(context.Context, *types.TipSet) ([]address.Address, error)
|
||||||
StateListActors(context.Context, *types.TipSet) ([]address.Address, error)
|
StateListActors(context.Context, *types.TipSet) ([]address.Address, error)
|
||||||
|
StateMarketBalance(context.Context, address.Address, *types.TipSet) (actors.StorageParticipantBalance, error)
|
||||||
|
StateMarketParticipants(context.Context, *types.TipSet) (map[string]actors.StorageParticipantBalance, error)
|
||||||
|
StateMarketDeals(context.Context, *types.TipSet) (map[string]actors.OnChainDeal, error)
|
||||||
|
|
||||||
PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error)
|
PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error)
|
||||||
PaychList(context.Context) ([]address.Address, error)
|
PaychList(context.Context) ([]address.Address, error)
|
||||||
@ -179,6 +183,9 @@ type Version struct {
|
|||||||
APIVersion uint32
|
APIVersion uint32
|
||||||
|
|
||||||
// TODO: git commit / os / genesis cid?
|
// TODO: git commit / os / genesis cid?
|
||||||
|
|
||||||
|
// Seconds
|
||||||
|
BlockDelay uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Version) String() string {
|
func (v Version) String() string {
|
||||||
@ -196,10 +203,9 @@ type Import struct {
|
|||||||
type DealInfo struct {
|
type DealInfo struct {
|
||||||
ProposalCid cid.Cid
|
ProposalCid cid.Cid
|
||||||
State DealState
|
State DealState
|
||||||
Miner address.Address
|
Provider address.Address
|
||||||
|
|
||||||
PieceRef cid.Cid
|
PieceRef []byte // cid bytes
|
||||||
CommP []byte
|
|
||||||
Size uint64
|
Size uint64
|
||||||
|
|
||||||
TotalPrice types.BigInt
|
TotalPrice types.BigInt
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/libp2p/go-libp2p-core/network"
|
"github.com/libp2p/go-libp2p-core/network"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/lotus/chain/address"
|
"github.com/filecoin-project/lotus/chain/address"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -85,20 +86,23 @@ type FullNodeStruct struct {
|
|||||||
ClientRetrieve func(ctx context.Context, order RetrievalOrder, path string) error `perm:"admin"`
|
ClientRetrieve func(ctx context.Context, order RetrievalOrder, path string) error `perm:"admin"`
|
||||||
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*types.SignedStorageAsk, error) `perm:"read"`
|
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*types.SignedStorageAsk, error) `perm:"read"`
|
||||||
|
|
||||||
StateMinerSectors func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"`
|
StateMinerSectors func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"`
|
||||||
StateMinerProvingSet func(context.Context, address.Address, *types.TipSet) ([]*SectorInfo, error) `perm:"read"`
|
StateMinerProvingSet func(context.Context, address.Address, *types.TipSet) ([]*SectorInfo, error) `perm:"read"`
|
||||||
StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"`
|
StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"`
|
||||||
StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"`
|
StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"`
|
||||||
StateMinerPeerID func(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) `perm:"read"`
|
StateMinerPeerID func(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) `perm:"read"`
|
||||||
StateMinerProvingPeriodEnd func(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) `perm:"read"`
|
StateMinerProvingPeriodEnd func(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) `perm:"read"`
|
||||||
StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"`
|
StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"`
|
||||||
StateReplay func(context.Context, *types.TipSet, cid.Cid) (*ReplayResults, error) `perm:"read"`
|
StateReplay func(context.Context, *types.TipSet, cid.Cid) (*ReplayResults, error) `perm:"read"`
|
||||||
StateGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"`
|
StateGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"`
|
||||||
StateReadState func(context.Context, *types.Actor, *types.TipSet) (*ActorState, error) `perm:"read"`
|
StateReadState func(context.Context, *types.Actor, *types.TipSet) (*ActorState, error) `perm:"read"`
|
||||||
StatePledgeCollateral func(context.Context, *types.TipSet) (types.BigInt, error) `perm:"read"`
|
StatePledgeCollateral func(context.Context, *types.TipSet) (types.BigInt, error) `perm:"read"`
|
||||||
StateWaitMsg func(context.Context, cid.Cid) (*MsgWait, error) `perm:"read"`
|
StateWaitMsg func(context.Context, cid.Cid) (*MsgWait, error) `perm:"read"`
|
||||||
StateListMiners func(context.Context, *types.TipSet) ([]address.Address, error) `perm:"read"`
|
StateListMiners func(context.Context, *types.TipSet) ([]address.Address, error) `perm:"read"`
|
||||||
StateListActors func(context.Context, *types.TipSet) ([]address.Address, error) `perm:"read"`
|
StateListActors func(context.Context, *types.TipSet) ([]address.Address, error) `perm:"read"`
|
||||||
|
StateMarketBalance func(context.Context, address.Address, *types.TipSet) (actors.StorageParticipantBalance, error) `perm:"read"`
|
||||||
|
StateMarketParticipants func(context.Context, *types.TipSet) (map[string]actors.StorageParticipantBalance, error) `perm:"read"`
|
||||||
|
StateMarketDeals func(context.Context, *types.TipSet) (map[string]actors.OnChainDeal, error) `perm:"read"`
|
||||||
|
|
||||||
PaychGet func(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error) `perm:"sign"`
|
PaychGet func(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error) `perm:"sign"`
|
||||||
PaychList func(context.Context) ([]address.Address, error) `perm:"read"`
|
PaychList func(context.Context) ([]address.Address, error) `perm:"read"`
|
||||||
@ -388,6 +392,18 @@ func (c *FullNodeStruct) StateListActors(ctx context.Context, ts *types.TipSet)
|
|||||||
return c.Internal.StateListActors(ctx, ts)
|
return c.Internal.StateListActors(ctx, ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) StateMarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (actors.StorageParticipantBalance, error) {
|
||||||
|
return c.Internal.StateMarketBalance(ctx, addr, ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) StateMarketParticipants(ctx context.Context, ts *types.TipSet) (map[string]actors.StorageParticipantBalance, error) {
|
||||||
|
return c.Internal.StateMarketParticipants(ctx, ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) StateMarketDeals(ctx context.Context, ts *types.TipSet) (map[string]actors.OnChainDeal, error) {
|
||||||
|
return c.Internal.StateMarketDeals(ctx, ts)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error) {
|
func (c *FullNodeStruct) PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error) {
|
||||||
return c.Internal.PaychGet(ctx, from, to, ensureFunds)
|
return c.Internal.PaychGet(ctx, from, to, ensureFunds)
|
||||||
}
|
}
|
||||||
|
15
api/types.go
15
api/types.go
@ -6,22 +6,21 @@ import (
|
|||||||
ma "github.com/multiformats/go-multiaddr"
|
ma "github.com/multiformats/go-multiaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DealState int
|
type DealState = uint64
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DealUnknown = DealState(iota)
|
DealUnknown = DealState(iota)
|
||||||
DealRejected
|
DealRejected // Provider didn't like the proposal
|
||||||
DealAccepted
|
DealAccepted // Proposal accepted, data moved
|
||||||
DealStarted
|
DealStaged // Data put into the sector
|
||||||
|
DealSealing // Data in process of being sealed
|
||||||
|
|
||||||
DealFailed
|
DealFailed
|
||||||
DealStaged
|
|
||||||
DealSealing
|
|
||||||
DealComplete
|
DealComplete
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
|
|
||||||
DealError // deal failed with an unexpected error
|
DealError // deal failed with an unexpected error
|
||||||
DealExpired
|
|
||||||
|
|
||||||
DealNoUpdate = DealUnknown
|
DealNoUpdate = DealUnknown
|
||||||
)
|
)
|
||||||
|
28
api/utils.go
Normal file
28
api/utils.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/address"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SignFunc = func(context.Context, []byte) (*types.Signature, error)
|
||||||
|
|
||||||
|
type Signer func(context.Context, address.Address, []byte) (*types.Signature, error)
|
||||||
|
|
||||||
|
type Signable interface {
|
||||||
|
Sign(context.Context, SignFunc) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func SignWith(ctx context.Context, signer Signer, addr address.Address, signable ...Signable) error {
|
||||||
|
for _, s := range signable {
|
||||||
|
err := s.Sign(ctx, func(ctx context.Context, b []byte) (*types.Signature, error) {
|
||||||
|
return signer(ctx, addr, b)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -30,7 +30,7 @@ const MaxVouchersPerDeal = 768 // roughly one voucher per 10h over a year
|
|||||||
// Consensus / Network
|
// Consensus / Network
|
||||||
|
|
||||||
// Seconds
|
// Seconds
|
||||||
const BlockDelay = 30
|
const BlockDelay = 3
|
||||||
|
|
||||||
// Seconds
|
// Seconds
|
||||||
const AllowableClockDrift = BlockDelay * 2
|
const AllowableClockDrift = BlockDelay * 2
|
||||||
@ -51,7 +51,7 @@ const RandomnessLookback = 20
|
|||||||
const ProvingPeriodDuration = 40
|
const ProvingPeriodDuration = 40
|
||||||
|
|
||||||
// Blocks
|
// Blocks
|
||||||
const PoSTChallangeTime = 20
|
const PoSTChallangeTime = 35
|
||||||
|
|
||||||
const PowerCollateralProportion = 5
|
const PowerCollateralProportion = 5
|
||||||
const PerCapitaCollateralProportion = 1
|
const PerCapitaCollateralProportion = 1
|
||||||
|
@ -162,7 +162,7 @@ func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams)
|
|||||||
|
|
||||||
func IsBuiltinActor(code cid.Cid) bool {
|
func IsBuiltinActor(code cid.Cid) bool {
|
||||||
switch code {
|
switch code {
|
||||||
case StorageMarketActorCodeCid, StorageMinerCodeCid, AccountActorCodeCid, InitActorCodeCid, MultisigActorCodeCid, PaymentChannelActorCodeCid:
|
case StorageMarketCodeCid, StoragePowerCodeCid, StorageMinerCodeCid, AccountCodeCid, InitCodeCid, MultisigCodeCid, PaymentChannelCodeCid:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
@ -170,7 +170,7 @@ func IsBuiltinActor(code cid.Cid) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IsSingletonActor(code cid.Cid) bool {
|
func IsSingletonActor(code cid.Cid) bool {
|
||||||
return code == StorageMarketActorCodeCid || code == InitActorCodeCid
|
return code == StoragePowerCodeCid || code == StorageMarketCodeCid || code == InitCodeCid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ias *InitActorState) AddActor(cst *hamt.CborIpldStore, addr address.Address) (address.Address, error) {
|
func (ias *InitActorState) AddActor(cst *hamt.CborIpldStore, addr address.Address) (address.Address, error) {
|
||||||
|
@ -18,8 +18,6 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const POST_SECTORS_COUNT = 8192
|
|
||||||
|
|
||||||
type StorageMinerActor struct{}
|
type StorageMinerActor struct{}
|
||||||
|
|
||||||
type StorageMinerActorState struct {
|
type StorageMinerActorState struct {
|
||||||
@ -100,29 +98,27 @@ type StorageMinerConstructorParams struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type maMethods struct {
|
type maMethods struct {
|
||||||
Constructor uint64
|
Constructor uint64
|
||||||
CommitSector uint64
|
CommitSector uint64
|
||||||
SubmitPoSt uint64
|
SubmitPoSt uint64
|
||||||
SlashStorageFault uint64
|
SlashStorageFault uint64
|
||||||
GetCurrentProvingSet uint64
|
GetCurrentProvingSet uint64
|
||||||
ArbitrateDeal uint64
|
ArbitrateDeal uint64
|
||||||
DePledge uint64
|
DePledge uint64
|
||||||
GetOwner uint64
|
GetOwner uint64
|
||||||
GetWorkerAddr uint64
|
GetWorkerAddr uint64
|
||||||
GetPower uint64
|
GetPower uint64
|
||||||
GetPeerID uint64
|
GetPeerID uint64
|
||||||
GetSectorSize uint64
|
GetSectorSize uint64
|
||||||
UpdatePeerID uint64
|
UpdatePeerID uint64
|
||||||
ChangeWorker uint64
|
ChangeWorker uint64
|
||||||
IsSlashed uint64
|
IsSlashed uint64
|
||||||
IsLate uint64
|
IsLate uint64
|
||||||
PaymentVerifyInclusion uint64
|
AddFaults uint64
|
||||||
PaymentVerifySector uint64
|
SlashConsensusFault uint64
|
||||||
AddFaults uint64
|
|
||||||
SlashConsensusFault uint64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var MAMethods = maMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
|
var MAMethods = maMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}
|
||||||
|
|
||||||
func (sma StorageMinerActor) Exports() []interface{} {
|
func (sma StorageMinerActor) Exports() []interface{} {
|
||||||
return []interface{}{
|
return []interface{}{
|
||||||
@ -142,10 +138,8 @@ func (sma StorageMinerActor) Exports() []interface{} {
|
|||||||
//14: sma.ChangeWorker,
|
//14: sma.ChangeWorker,
|
||||||
//15: sma.IsSlashed,
|
//15: sma.IsSlashed,
|
||||||
//16: sma.IsLate,
|
//16: sma.IsLate,
|
||||||
17: sma.PaymentVerifyInclusion,
|
17: sma.AddFaults,
|
||||||
18: sma.PaymentVerifySector,
|
18: sma.SlashConsensusFault,
|
||||||
19: sma.AddFaults,
|
|
||||||
20: sma.SlashConsensusFault,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,15 +199,18 @@ func (sma StorageMinerActor) StorageMinerConstructor(act *types.Actor, vmctx typ
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommitSectorParams struct {
|
type OnChainSealVerifyInfo struct {
|
||||||
SectorID uint64
|
CommD []byte // TODO: update proofs code
|
||||||
CommD []byte
|
|
||||||
CommR []byte
|
CommR []byte
|
||||||
CommRStar []byte
|
CommRStar []byte
|
||||||
Proof []byte
|
|
||||||
|
//Epoch uint64
|
||||||
|
Proof []byte
|
||||||
|
DealIDs []uint64
|
||||||
|
SectorNumber uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContext, params *CommitSectorParams) ([]byte, ActorError) {
|
func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContext, params *OnChainSealVerifyInfo) ([]byte, ActorError) {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
oldstate, self, err := loadState(vmctx)
|
oldstate, self, err := loadState(vmctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -235,7 +232,7 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure the miner isnt trying to submit a pre-existing sector
|
// make sure the miner isnt trying to submit a pre-existing sector
|
||||||
unique, err := SectorIsUnique(ctx, vmctx.Storage(), self.Sectors, params.SectorID)
|
unique, err := SectorIsUnique(ctx, vmctx.Storage(), self.Sectors, params.SectorNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -247,6 +244,7 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex
|
|||||||
futurePower := types.BigAdd(self.Power, mi.SectorSize)
|
futurePower := types.BigAdd(self.Power, mi.SectorSize)
|
||||||
collateralRequired := CollateralForPower(futurePower)
|
collateralRequired := CollateralForPower(futurePower)
|
||||||
|
|
||||||
|
// TODO: grab from market?
|
||||||
if act.Balance.LessThan(collateralRequired) {
|
if act.Balance.LessThan(collateralRequired) {
|
||||||
return nil, aerrors.New(3, "not enough collateral")
|
return nil, aerrors.New(3, "not enough collateral")
|
||||||
}
|
}
|
||||||
@ -254,7 +252,7 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex
|
|||||||
// Note: There must exist a unique index in the miner's sector set for each
|
// Note: There must exist a unique index in the miner's sector set for each
|
||||||
// sector ID. The `faults`, `recovered`, and `done` parameters of the
|
// sector ID. The `faults`, `recovered`, and `done` parameters of the
|
||||||
// SubmitPoSt method express indices into this sector set.
|
// SubmitPoSt method express indices into this sector set.
|
||||||
nssroot, err := AddToSectorSet(ctx, vmctx.Storage(), self.Sectors, params.SectorID, params.CommR, params.CommD)
|
nssroot, err := AddToSectorSet(ctx, vmctx.Storage(), self.Sectors, params.SectorNumber, params.CommR, params.CommD)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -286,7 +284,15 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
activateParams, err := SerializeParams(&ActivateStorageDealsParams{
|
||||||
|
Deals: params.DealIDs,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = vmctx.Send(StorageMarketAddress, SMAMethods.ActivateStorageDeals, types.NewInt(0), activateParams)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubmitPoStParams struct {
|
type SubmitPoStParams struct {
|
||||||
@ -433,7 +439,7 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = vmctx.Send(StorageMarketAddress, SPAMethods.UpdateStorage, types.NewInt(0), enc)
|
_, err = vmctx.Send(StoragePowerAddress, SPAMethods.UpdateStorage, types.NewInt(0), enc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -511,8 +517,8 @@ func GetFromSectorSet(ctx context.Context, s types.Storage, ss cid.Cid, sectorID
|
|||||||
return true, comms[0], comms[1], nil
|
return true, comms[0], comms[1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidatePoRep(maddr address.Address, ssize types.BigInt, params *CommitSectorParams) (bool, ActorError) {
|
func ValidatePoRep(maddr address.Address, ssize types.BigInt, params *OnChainSealVerifyInfo) (bool, ActorError) {
|
||||||
ok, err := sectorbuilder.VerifySeal(ssize.Uint64(), params.CommR, params.CommD, params.CommRStar, maddr, params.SectorID, params.Proof)
|
ok, err := sectorbuilder.VerifySeal(ssize.Uint64(), params.CommR, params.CommD, params.CommRStar, maddr, params.SectorNumber, params.Proof)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, aerrors.Absorb(err, 25, "verify seal failed")
|
return false, aerrors.Absorb(err, 25, "verify seal failed")
|
||||||
}
|
}
|
||||||
@ -634,84 +640,6 @@ type PaymentVerifyParams struct {
|
|||||||
Proof []byte
|
Proof []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type PieceInclVoucherData struct { // TODO: Update spec at https://github.com/filecoin-project/specs/blob/master/actors.md#paymentverify
|
|
||||||
CommP []byte
|
|
||||||
PieceSize types.BigInt
|
|
||||||
}
|
|
||||||
|
|
||||||
type InclusionProof struct {
|
|
||||||
Sector uint64 // for CommD, also verifies the sector is in sector set
|
|
||||||
Proof []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sma StorageMinerActor) PaymentVerifyInclusion(act *types.Actor, vmctx types.VMContext, params *PaymentVerifyParams) ([]byte, ActorError) {
|
|
||||||
// params.Extra - PieceInclVoucherData
|
|
||||||
// params.Proof - InclusionProof
|
|
||||||
|
|
||||||
_, self, aerr := loadState(vmctx)
|
|
||||||
if aerr != nil {
|
|
||||||
return nil, aerr
|
|
||||||
}
|
|
||||||
mi, aerr := loadMinerInfo(vmctx, self)
|
|
||||||
if aerr != nil {
|
|
||||||
return nil, aerr
|
|
||||||
}
|
|
||||||
|
|
||||||
var voucherData PieceInclVoucherData
|
|
||||||
if err := cbor.DecodeInto(params.Extra, &voucherData); err != nil {
|
|
||||||
return nil, aerrors.Absorb(err, 2, "failed to decode storage voucher data for verification")
|
|
||||||
}
|
|
||||||
var proof InclusionProof
|
|
||||||
if err := cbor.DecodeInto(params.Proof, &proof); err != nil {
|
|
||||||
return nil, aerrors.Absorb(err, 3, "failed to decode storage payment proof")
|
|
||||||
}
|
|
||||||
|
|
||||||
ok, _, commD, aerr := GetFromSectorSet(context.TODO(), vmctx.Storage(), self.Sectors, proof.Sector)
|
|
||||||
if aerr != nil {
|
|
||||||
return nil, aerr
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return nil, aerrors.New(4, "miner does not have required sector")
|
|
||||||
}
|
|
||||||
|
|
||||||
ok, err := sectorbuilder.VerifyPieceInclusionProof(mi.SectorSize.Uint64(), voucherData.PieceSize.Uint64(), voucherData.CommP, commD, proof.Proof)
|
|
||||||
if err != nil {
|
|
||||||
return nil, aerrors.Absorb(err, 5, "verify piece inclusion proof failed")
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return nil, aerrors.New(6, "piece inclusion proof was invalid")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sma StorageMinerActor) PaymentVerifySector(act *types.Actor, vmctx types.VMContext, params *PaymentVerifyParams) ([]byte, ActorError) {
|
|
||||||
// params.Extra - BigInt - sector id
|
|
||||||
// params.Proof - nil
|
|
||||||
|
|
||||||
_, self, aerr := loadState(vmctx)
|
|
||||||
if aerr != nil {
|
|
||||||
return nil, aerr
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: ensure no sector ID reusability within related deal lifetime
|
|
||||||
sector := types.BigFromBytes(params.Extra)
|
|
||||||
|
|
||||||
if len(params.Proof) > 0 {
|
|
||||||
return nil, aerrors.New(1, "unexpected proof bytes")
|
|
||||||
}
|
|
||||||
|
|
||||||
ok, _, _, aerr := GetFromSectorSet(context.TODO(), vmctx.Storage(), self.Sectors, sector.Uint64())
|
|
||||||
if aerr != nil {
|
|
||||||
return nil, aerr
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return nil, aerrors.New(2, "miner does not have required sector")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type AddFaultsParams struct {
|
type AddFaultsParams struct {
|
||||||
Faults types.BitField
|
Faults types.BitField
|
||||||
}
|
}
|
||||||
@ -753,7 +681,7 @@ type MinerSlashConsensusFault struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sma StorageMinerActor) SlashConsensusFault(act *types.Actor, vmctx types.VMContext, params *MinerSlashConsensusFault) ([]byte, ActorError) {
|
func (sma StorageMinerActor) SlashConsensusFault(act *types.Actor, vmctx types.VMContext, params *MinerSlashConsensusFault) ([]byte, ActorError) {
|
||||||
if vmctx.Message().From != StorageMarketAddress {
|
if vmctx.Message().From != StoragePowerAddress {
|
||||||
return nil, aerrors.New(1, "SlashConsensusFault may only be called by the storage market actor")
|
return nil, aerrors.New(1, "SlashConsensusFault may only be called by the storage market actor")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ func TestMultiSigCreate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
h := NewHarness(t, opts...)
|
h := NewHarness(t, opts...)
|
||||||
ret, _ := h.CreateActor(t, creatorAddr, actors.MultisigActorCodeCid,
|
ret, _ := h.CreateActor(t, creatorAddr, actors.MultisigCodeCid,
|
||||||
&actors.MultiSigConstructorParams{
|
&actors.MultiSigConstructorParams{
|
||||||
Signers: []address.Address{creatorAddr, sig1Addr, sig2Addr},
|
Signers: []address.Address{creatorAddr, sig1Addr, sig2Addr},
|
||||||
Required: 2,
|
Required: 2,
|
||||||
@ -49,7 +49,7 @@ func TestMultiSigOps(t *testing.T) {
|
|||||||
HarnessAddr(&sig1Addr, 100000),
|
HarnessAddr(&sig1Addr, 100000),
|
||||||
HarnessAddr(&sig2Addr, 100000),
|
HarnessAddr(&sig2Addr, 100000),
|
||||||
HarnessAddr(&outsideAddr, 100000),
|
HarnessAddr(&outsideAddr, 100000),
|
||||||
HarnessActor(&multSigAddr, &creatorAddr, actors.MultisigActorCodeCid,
|
HarnessActor(&multSigAddr, &creatorAddr, actors.MultisigCodeCid,
|
||||||
func() cbg.CBORMarshaler {
|
func() cbg.CBORMarshaler {
|
||||||
return &actors.MultiSigConstructorParams{
|
return &actors.MultiSigConstructorParams{
|
||||||
Signers: []address.Address{creatorAddr, sig1Addr, sig2Addr},
|
Signers: []address.Address{creatorAddr, sig1Addr, sig2Addr},
|
||||||
|
@ -18,7 +18,7 @@ func TestPaychCreate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
h := NewHarness(t, opts...)
|
h := NewHarness(t, opts...)
|
||||||
ret, _ := h.CreateActor(t, creatorAddr, actors.PaymentChannelActorCodeCid,
|
ret, _ := h.CreateActor(t, creatorAddr, actors.PaymentChannelCodeCid,
|
||||||
&actors.PCAConstructorParams{
|
&actors.PCAConstructorParams{
|
||||||
To: targetAddr,
|
To: targetAddr,
|
||||||
})
|
})
|
||||||
@ -47,7 +47,7 @@ func TestPaychUpdate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
h := NewHarness(t, opts...)
|
h := NewHarness(t, opts...)
|
||||||
ret, _ := h.CreateActor(t, creatorAddr, actors.PaymentChannelActorCodeCid,
|
ret, _ := h.CreateActor(t, creatorAddr, actors.PaymentChannelCodeCid,
|
||||||
&actors.PCAConstructorParams{
|
&actors.PCAConstructorParams{
|
||||||
To: targetAddr,
|
To: targetAddr,
|
||||||
})
|
})
|
||||||
|
604
chain/actors/actor_storagemarket.go
Normal file
604
chain/actors/actor_storagemarket.go
Normal file
@ -0,0 +1,604 @@
|
|||||||
|
package actors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-amt-ipld"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
"github.com/ipfs/go-hamt-ipld"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/address"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StorageMarketActor struct{}
|
||||||
|
|
||||||
|
type smaMethods struct {
|
||||||
|
Constructor uint64
|
||||||
|
WithdrawBalance uint64
|
||||||
|
AddBalance uint64
|
||||||
|
CheckLockedBalance uint64
|
||||||
|
PublishStorageDeals uint64
|
||||||
|
HandleCronAction uint64
|
||||||
|
SettleExpiredDeals uint64
|
||||||
|
ProcessStorageDealsPayment uint64
|
||||||
|
SlashStorageDealCollateral uint64
|
||||||
|
GetLastExpirationFromDealIDs uint64
|
||||||
|
ActivateStorageDeals uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
var SMAMethods = smaMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
|
||||||
|
|
||||||
|
func (sma StorageMarketActor) Exports() []interface{} {
|
||||||
|
return []interface{}{
|
||||||
|
2: sma.WithdrawBalance,
|
||||||
|
3: sma.AddBalance,
|
||||||
|
// 4: sma.CheckLockedBalance,
|
||||||
|
5: sma.PublishStorageDeals,
|
||||||
|
// 6: sma.HandleCronAction,
|
||||||
|
// 7: sma.SettleExpiredDeals,
|
||||||
|
// 8: sma.ProcessStorageDealsPayment,
|
||||||
|
// 9: sma.SlashStorageDealCollateral,
|
||||||
|
// 10: sma.GetLastExpirationFromDealIDs,
|
||||||
|
11: sma.ActivateStorageDeals, // TODO: move under PublishStorageDeals after specs team approves
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type StorageParticipantBalance struct {
|
||||||
|
Locked types.BigInt
|
||||||
|
Available types.BigInt
|
||||||
|
}
|
||||||
|
|
||||||
|
type StorageMarketState struct {
|
||||||
|
Balances cid.Cid // hamt<addr, StorageParticipantBalance>
|
||||||
|
Deals cid.Cid // amt<StorageDeal>
|
||||||
|
|
||||||
|
NextDealID uint64 // TODO: spec
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Drop in favour of car storage
|
||||||
|
type SerializationMode = uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
SerializationUnixFSv0 = iota
|
||||||
|
// IPLD / car
|
||||||
|
)
|
||||||
|
|
||||||
|
type StorageDealProposal struct {
|
||||||
|
PieceRef []byte // cid bytes // TODO: spec says to use cid.Cid, probably not a good idea
|
||||||
|
PieceSize uint64
|
||||||
|
PieceSerialization SerializationMode // Needs to be here as it tells how data in the sector maps to PieceRef cid
|
||||||
|
|
||||||
|
Client address.Address
|
||||||
|
Provider address.Address
|
||||||
|
|
||||||
|
ProposalExpiration uint64
|
||||||
|
Duration uint64 // TODO: spec proposes 'DealExpiration', but that's awkward as it
|
||||||
|
// doesn't tell when the deal actually starts, so the price per block is impossible to
|
||||||
|
// calculate. It also doesn't incentivize the miner to seal / activate sooner, as he
|
||||||
|
// still get's paid the full amount specified in the deal
|
||||||
|
//
|
||||||
|
// Changing to duration makes sure that the price-per-block is defined, and the miner
|
||||||
|
// doesn't get paid when not storing the sector
|
||||||
|
|
||||||
|
StoragePrice types.BigInt
|
||||||
|
StorageCollateral types.BigInt
|
||||||
|
|
||||||
|
ProposerSignature *types.Signature
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignFunc = func(context.Context, []byte) (*types.Signature, error)
|
||||||
|
|
||||||
|
func (sdp *StorageDealProposal) Sign(ctx context.Context, sign SignFunc) error {
|
||||||
|
if sdp.ProposerSignature != nil {
|
||||||
|
return xerrors.New("signature already present in StorageDealProposal")
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := sdp.MarshalCBOR(&buf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sig, err := sign(ctx, buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sdp.ProposerSignature = sig
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sdp *StorageDealProposal) Verify() error {
|
||||||
|
unsigned := *sdp
|
||||||
|
unsigned.ProposerSignature = nil
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := unsigned.MarshalCBOR(&buf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sdp.ProposerSignature.Verify(sdp.Client, buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *StorageDeal) Sign(ctx context.Context, sign SignFunc) error {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := d.Proposal.MarshalCBOR(&buf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sig, err := sign(ctx, buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.CounterSignature = sig
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *StorageDeal) Verify(proposerWorker address.Address) error {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := d.Proposal.MarshalCBOR(&buf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.CounterSignature.Verify(proposerWorker, buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
type StorageDeal struct {
|
||||||
|
Proposal StorageDealProposal
|
||||||
|
CounterSignature *types.Signature
|
||||||
|
}
|
||||||
|
|
||||||
|
type OnChainDeal struct {
|
||||||
|
Deal StorageDeal
|
||||||
|
ActivationEpoch uint64 // 0 = inactive
|
||||||
|
}
|
||||||
|
|
||||||
|
type WithdrawBalanceParams struct {
|
||||||
|
Balance types.BigInt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sma StorageMarketActor) WithdrawBalance(act *types.Actor, vmctx types.VMContext, params *WithdrawBalanceParams) ([]byte, ActorError) {
|
||||||
|
// TODO: (spec) this should be 2-stage
|
||||||
|
|
||||||
|
var self StorageMarketState
|
||||||
|
old := vmctx.Storage().GetHead()
|
||||||
|
if err := vmctx.Storage().Get(old, &self); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b, bnd, err := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), self.Balances, vmctx.Message().From)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.Wrap(err, "could not get balance")
|
||||||
|
}
|
||||||
|
|
||||||
|
balance := b[0]
|
||||||
|
|
||||||
|
if balance.Available.LessThan(params.Balance) {
|
||||||
|
return nil, aerrors.Newf(1, "can not withdraw more funds than available: %s > %s", params.Balance, b[0].Available)
|
||||||
|
}
|
||||||
|
|
||||||
|
balance.Available = types.BigSub(balance.Available, params.Balance)
|
||||||
|
|
||||||
|
_, err = vmctx.Send(vmctx.Message().From, 0, params.Balance, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.Wrap(err, "sending funds failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
bcid, err := setMarketBalances(vmctx, bnd, map[address.Address]StorageParticipantBalance{
|
||||||
|
vmctx.Message().From: balance,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Balances = bcid
|
||||||
|
|
||||||
|
nroot, err := vmctx.Storage().Put(&self)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, vmctx.Storage().Commit(old, nroot)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sma StorageMarketActor) AddBalance(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||||
|
var self StorageMarketState
|
||||||
|
old := vmctx.Storage().GetHead()
|
||||||
|
if err := vmctx.Storage().Get(old, &self); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b, bnd, err := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), self.Balances, vmctx.Message().From)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.Wrap(err, "could not get balance")
|
||||||
|
}
|
||||||
|
|
||||||
|
balance := b[0]
|
||||||
|
|
||||||
|
balance.Available = types.BigAdd(balance.Available, vmctx.Message().Value)
|
||||||
|
|
||||||
|
bcid, err := setMarketBalances(vmctx, bnd, map[address.Address]StorageParticipantBalance{
|
||||||
|
vmctx.Message().From: balance,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Balances = bcid
|
||||||
|
|
||||||
|
nroot, err := vmctx.Storage().Put(&self)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, vmctx.Storage().Commit(old, nroot)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setMarketBalances(vmctx types.VMContext, nd *hamt.Node, set map[address.Address]StorageParticipantBalance) (cid.Cid, ActorError) {
|
||||||
|
for addr, b := range set {
|
||||||
|
balance := b // to stop linter complaining
|
||||||
|
if err := nd.Set(vmctx.Context(), string(addr.Bytes()), &balance); err != nil {
|
||||||
|
return cid.Undef, aerrors.HandleExternalError(err, "setting new balance")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := nd.Flush(vmctx.Context()); err != nil {
|
||||||
|
return cid.Undef, aerrors.HandleExternalError(err, "flushing balance hamt")
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := vmctx.Ipld().Put(vmctx.Context(), nd)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, aerrors.HandleExternalError(err, "failed to balances storage")
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMarketBalances(ctx context.Context, store *hamt.CborIpldStore, rcid cid.Cid, addrs ...address.Address) ([]StorageParticipantBalance, *hamt.Node, ActorError) {
|
||||||
|
nd, err := hamt.LoadNode(ctx, store, rcid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, aerrors.HandleExternalError(err, "failed to load miner set")
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make([]StorageParticipantBalance, len(addrs))
|
||||||
|
|
||||||
|
for i, a := range addrs {
|
||||||
|
var balance StorageParticipantBalance
|
||||||
|
err = nd.Find(ctx, string(a.Bytes()), &balance)
|
||||||
|
switch err {
|
||||||
|
case hamt.ErrNotFound:
|
||||||
|
out[i] = StorageParticipantBalance{
|
||||||
|
Locked: types.NewInt(0),
|
||||||
|
Available: types.NewInt(0),
|
||||||
|
}
|
||||||
|
case nil:
|
||||||
|
out[i] = balance
|
||||||
|
default:
|
||||||
|
return nil, nil, aerrors.HandleExternalError(err, "failed to do set lookup")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nd, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (sma StorageMarketActor) CheckLockedBalance(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
type PublishStorageDealsParams struct {
|
||||||
|
Deals []StorageDeal
|
||||||
|
}
|
||||||
|
|
||||||
|
type PublishStorageDealResponse struct {
|
||||||
|
DealIDs []uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sma StorageMarketActor) PublishStorageDeals(act *types.Actor, vmctx types.VMContext, params *PublishStorageDealsParams) ([]byte, ActorError) {
|
||||||
|
var self StorageMarketState
|
||||||
|
old := vmctx.Storage().GetHead()
|
||||||
|
if err := vmctx.Storage().Get(old, &self); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
deals, err := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Deals)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.HandleExternalError(err, "loading deals amt")
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: handle duplicate deals
|
||||||
|
|
||||||
|
if len(params.Deals) == 0 {
|
||||||
|
return nil, aerrors.New(1, "no storage deals in params.Deals")
|
||||||
|
}
|
||||||
|
|
||||||
|
out := PublishStorageDealResponse{
|
||||||
|
DealIDs: make([]uint64, len(params.Deals)),
|
||||||
|
}
|
||||||
|
|
||||||
|
workerBytes, aerr := vmctx.Send(params.Deals[0].Proposal.Provider, MAMethods.GetWorkerAddr, types.NewInt(0), nil)
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
providerWorker, err := address.NewFromBytes(workerBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.HandleExternalError(err, "parsing provider worker address bytes")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: REVIEW: Do we want to check if provider exists in the power actor?
|
||||||
|
|
||||||
|
for i, deal := range params.Deals {
|
||||||
|
if err := self.validateDeal(vmctx, deal, providerWorker); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err := deals.Set(self.NextDealID, &OnChainDeal{Deal: deal})
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.HandleExternalError(err, "setting deal in deal AMT")
|
||||||
|
}
|
||||||
|
out.DealIDs[i] = self.NextDealID
|
||||||
|
|
||||||
|
self.NextDealID++
|
||||||
|
}
|
||||||
|
|
||||||
|
dealsCid, err := deals.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.HandleExternalError(err, "saving deals AMT")
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Deals = dealsCid
|
||||||
|
|
||||||
|
nroot, err := vmctx.Storage().Put(&self)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.HandleExternalError(err, "storing state failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
aerr = vmctx.Storage().Commit(old, nroot)
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
|
||||||
|
var outBuf bytes.Buffer
|
||||||
|
if err := out.MarshalCBOR(&outBuf); err != nil {
|
||||||
|
return nil, aerrors.HandleExternalError(err, "serialising output")
|
||||||
|
}
|
||||||
|
|
||||||
|
return outBuf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *StorageMarketState) validateDeal(vmctx types.VMContext, deal StorageDeal, providerWorker address.Address) aerrors.ActorError {
|
||||||
|
if vmctx.BlockHeight() > deal.Proposal.ProposalExpiration {
|
||||||
|
return aerrors.New(1, "deal proposal already expired")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := deal.Proposal.Verify(); err != nil {
|
||||||
|
return aerrors.Absorb(err, 2, "verifying proposer signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := deal.Verify(providerWorker)
|
||||||
|
if err != nil {
|
||||||
|
return aerrors.Absorb(err, 2, "verifying provider signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: maybe this is actually fine
|
||||||
|
if vmctx.Message().From != providerWorker && vmctx.Message().From != deal.Proposal.Client {
|
||||||
|
return aerrors.New(4, "message not sent by deal participant")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do some caching (changes gas so needs to be in spec too)
|
||||||
|
b, bnd, aerr := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), st.Balances, deal.Proposal.Client, providerWorker)
|
||||||
|
if aerr != nil {
|
||||||
|
return aerrors.Wrap(aerr, "getting client, and provider balances")
|
||||||
|
}
|
||||||
|
clientBalance := b[0]
|
||||||
|
providerBalance := b[1]
|
||||||
|
|
||||||
|
if clientBalance.Available.LessThan(deal.Proposal.StoragePrice) {
|
||||||
|
return aerrors.Newf(5, "client doesn't have enough available funds to cover StoragePrice; %d < %d", clientBalance.Available, deal.Proposal.StoragePrice)
|
||||||
|
}
|
||||||
|
|
||||||
|
clientBalance = lockFunds(clientBalance, deal.Proposal.StoragePrice)
|
||||||
|
|
||||||
|
// TODO: REVIEW: Not clear who pays for this
|
||||||
|
if providerBalance.Available.LessThan(deal.Proposal.StorageCollateral) {
|
||||||
|
return aerrors.Newf(6, "provider doesn't have enough available funds to cover StorageCollateral; %d < %d", providerBalance.Available, deal.Proposal.StorageCollateral)
|
||||||
|
}
|
||||||
|
|
||||||
|
providerBalance = lockFunds(providerBalance, deal.Proposal.StorageCollateral)
|
||||||
|
|
||||||
|
// TODO: piece checks (e.g. size > sectorSize)?
|
||||||
|
|
||||||
|
bcid, aerr := setMarketBalances(vmctx, bnd, map[address.Address]StorageParticipantBalance{
|
||||||
|
deal.Proposal.Client: clientBalance,
|
||||||
|
providerWorker: providerBalance,
|
||||||
|
})
|
||||||
|
if aerr != nil {
|
||||||
|
return aerr
|
||||||
|
}
|
||||||
|
|
||||||
|
st.Balances = bcid
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ActivateStorageDealsParams struct {
|
||||||
|
Deals []uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sma StorageMarketActor) ActivateStorageDeals(act *types.Actor, vmctx types.VMContext, params *ActivateStorageDealsParams) ([]byte, ActorError) {
|
||||||
|
var self StorageMarketState
|
||||||
|
old := vmctx.Storage().GetHead()
|
||||||
|
if err := vmctx.Storage().Get(old, &self); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
deals, err := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Deals)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: kind of annoying that this can be caused by gas, otherwise could be fatal
|
||||||
|
return nil, aerrors.HandleExternalError(err, "loading deals amt")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, deal := range params.Deals {
|
||||||
|
var dealInfo OnChainDeal
|
||||||
|
if err := deals.Get(deal, &dealInfo); err != nil {
|
||||||
|
if _, is := err.(*amt.ErrNotFound); is {
|
||||||
|
return nil, aerrors.New(3, "deal not found")
|
||||||
|
}
|
||||||
|
return nil, aerrors.HandleExternalError(err, "getting deal info failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if vmctx.Message().From != dealInfo.Deal.Proposal.Provider {
|
||||||
|
return nil, aerrors.New(1, "ActivateStorageDeals can only be called by the deal provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
if vmctx.BlockHeight() > dealInfo.Deal.Proposal.ProposalExpiration {
|
||||||
|
return nil, aerrors.New(2, "deal cannot be activated: proposal expired")
|
||||||
|
}
|
||||||
|
|
||||||
|
if dealInfo.ActivationEpoch > 0 {
|
||||||
|
// this probably can't happen in practice
|
||||||
|
return nil, aerrors.New(3, "deal already active")
|
||||||
|
}
|
||||||
|
|
||||||
|
dealInfo.ActivationEpoch = vmctx.BlockHeight()
|
||||||
|
|
||||||
|
if err := deals.Set(deal, &dealInfo); err != nil {
|
||||||
|
return nil, aerrors.HandleExternalError(err, "setting deal info in AMT failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dealsCid, err := deals.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.HandleExternalError(err, "saving deals AMT")
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Deals = dealsCid
|
||||||
|
|
||||||
|
nroot, err := vmctx.Storage().Put(&self)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.HandleExternalError(err, "storing state failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
aerr := vmctx.Storage().Commit(old, nroot)
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcessStorageDealsPaymentParams struct {
|
||||||
|
DealIDs []uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sma StorageMarketActor) ProcessStorageDealsPayment(act *types.Actor, vmctx types.VMContext, params *ProcessStorageDealsPaymentParams) ([]byte, ActorError) {
|
||||||
|
var self StorageMarketState
|
||||||
|
old := vmctx.Storage().GetHead()
|
||||||
|
if err := vmctx.Storage().Get(old, &self); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
deals, err := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Deals)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: kind of annoying that this can be caused by gas, otherwise could be fatal
|
||||||
|
return nil, aerrors.HandleExternalError(err, "loading deals amt")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Would be nice if send could assert actor type
|
||||||
|
workerBytes, aerr := vmctx.Send(vmctx.Message().From, MAMethods.GetWorkerAddr, types.NewInt(0), nil)
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
providerWorker, err := address.NewFromBytes(workerBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.HandleExternalError(err, "parsing provider worker address bytes")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, deal := range params.DealIDs {
|
||||||
|
var dealInfo OnChainDeal
|
||||||
|
if err := deals.Get(deal, &dealInfo); err != nil {
|
||||||
|
if _, is := err.(*amt.ErrNotFound); is {
|
||||||
|
return nil, aerrors.New(2, "deal not found")
|
||||||
|
}
|
||||||
|
return nil, aerrors.HandleExternalError(err, "getting deal info failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if dealInfo.Deal.Proposal.Provider != vmctx.Message().From {
|
||||||
|
return nil, aerrors.New(3, "ProcessStorageDealsPayment can only be called by deal provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
if vmctx.BlockHeight() < dealInfo.ActivationEpoch {
|
||||||
|
// TODO: This is probably fatal
|
||||||
|
return nil, aerrors.New(4, "ActivationEpoch lower than block height")
|
||||||
|
}
|
||||||
|
|
||||||
|
if vmctx.BlockHeight() > dealInfo.ActivationEpoch+dealInfo.Deal.Proposal.Duration {
|
||||||
|
// Deal expired, miner should drop it
|
||||||
|
// TODO: process payment for the remainder of last proving period
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: check math (written on a plane, also tired)
|
||||||
|
// TODO: division is hard, this more than likely has some off-by-one issue
|
||||||
|
toPay := types.BigDiv(types.BigMul(dealInfo.Deal.Proposal.StoragePrice, types.NewInt(build.ProvingPeriodDuration)), types.NewInt(dealInfo.Deal.Proposal.Duration))
|
||||||
|
|
||||||
|
b, bnd, aerr := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), self.Balances, dealInfo.Deal.Proposal.Client, providerWorker)
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
clientBal := b[0]
|
||||||
|
providerBal := b[1]
|
||||||
|
|
||||||
|
clientBal.Locked, providerBal.Available = transferFunds(clientBal.Locked, providerBal.Available, toPay)
|
||||||
|
|
||||||
|
// TODO: call set once
|
||||||
|
bcid, aerr := setMarketBalances(vmctx, bnd, map[address.Address]StorageParticipantBalance{
|
||||||
|
dealInfo.Deal.Proposal.Client: clientBal,
|
||||||
|
providerWorker: providerBal,
|
||||||
|
})
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Balances = bcid
|
||||||
|
}
|
||||||
|
|
||||||
|
nroot, err := vmctx.Storage().Put(&self)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.HandleExternalError(err, "storing state failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
aerr = vmctx.Storage().Commit(old, nroot)
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lockFunds(p StorageParticipantBalance, amt types.BigInt) StorageParticipantBalance {
|
||||||
|
p.Available, p.Locked = transferFunds(p.Available, p.Locked, amt)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func transferFunds(from, to, amt types.BigInt) (types.BigInt, types.BigInt) {
|
||||||
|
// TODO: some asserts
|
||||||
|
return types.BigSub(from, amt), types.BigAdd(to, amt)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (sma StorageMarketActor) HandleCronAction(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sma StorageMarketActor) SettleExpiredDeals(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sma StorageMarketActor) SlashStorageDealCollateral(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sma StorageMarketActor) GetLastExpirationFromDealIDs(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
@ -87,7 +87,7 @@ func (spa StoragePowerActor) CreateStorageMiner(act *types.Actor, vmctx types.VM
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ret, err := vmctx.Send(InitActorAddress, IAMethods.Exec, vmctx.Message().Value, encoded)
|
ret, err := vmctx.Send(InitAddress, IAMethods.Exec, vmctx.Message().Value, encoded)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) {
|
|||||||
// cheating the bootstrapping problem
|
// cheating the bootstrapping problem
|
||||||
cheatStorageMarketTotal(t, h.vm, h.cs.Blockstore())
|
cheatStorageMarketTotal(t, h.vm, h.cs.Blockstore())
|
||||||
|
|
||||||
ret, _ := h.InvokeWithValue(t, ownerAddr, StorageMarketAddress, SPAMethods.CreateStorageMiner,
|
ret, _ := h.InvokeWithValue(t, ownerAddr, StoragePowerAddress, SPAMethods.CreateStorageMiner,
|
||||||
types.NewInt(500000),
|
types.NewInt(500000),
|
||||||
&CreateStorageMinerParams{
|
&CreateStorageMinerParams{
|
||||||
Owner: ownerAddr,
|
Owner: ownerAddr,
|
||||||
@ -52,7 +52,7 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SPAMethods.IsMiner,
|
ret, _ := h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.IsMiner,
|
||||||
&IsMinerParam{Addr: minerAddr})
|
&IsMinerParam{Addr: minerAddr})
|
||||||
ApplyOK(t, ret)
|
ApplyOK(t, ret)
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SPAMethods.PowerLookup,
|
ret, _ := h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.PowerLookup,
|
||||||
&PowerLookupParams{Miner: minerAddr})
|
&PowerLookupParams{Miner: minerAddr})
|
||||||
ApplyOK(t, ret)
|
ApplyOK(t, ret)
|
||||||
power := types.BigFromBytes(ret.Return)
|
power := types.BigFromBytes(ret.Return)
|
||||||
@ -93,7 +93,7 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) {
|
|||||||
signBlock(t, h.w, workerAddr, b1)
|
signBlock(t, h.w, workerAddr, b1)
|
||||||
signBlock(t, h.w, workerAddr, b2)
|
signBlock(t, h.w, workerAddr, b2)
|
||||||
|
|
||||||
ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SPAMethods.ArbitrateConsensusFault,
|
ret, _ := h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.ArbitrateConsensusFault,
|
||||||
&ArbitrateConsensusFaultParams{
|
&ArbitrateConsensusFaultParams{
|
||||||
Block1: b1,
|
Block1: b1,
|
||||||
Block2: b2,
|
Block2: b2,
|
||||||
@ -102,13 +102,13 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SPAMethods.PowerLookup,
|
ret, _ := h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.PowerLookup,
|
||||||
&PowerLookupParams{Miner: minerAddr})
|
&PowerLookupParams{Miner: minerAddr})
|
||||||
assert.Equal(t, ret.ExitCode, byte(1))
|
assert.Equal(t, ret.ExitCode, byte(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SPAMethods.IsMiner, &IsMinerParam{minerAddr})
|
ret, _ := h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.IsMiner, &IsMinerParam{minerAddr})
|
||||||
ApplyOK(t, ret)
|
ApplyOK(t, ret)
|
||||||
assert.Equal(t, ret.Return, cbg.CborBoolFalse)
|
assert.Equal(t, ret.Return, cbg.CborBoolFalse)
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) {
|
|||||||
func cheatStorageMarketTotal(t *testing.T, vm *vm.VM, bs bstore.Blockstore) {
|
func cheatStorageMarketTotal(t *testing.T, vm *vm.VM, bs bstore.Blockstore) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
sma, err := vm.StateTree().GetActor(StorageMarketAddress)
|
sma, err := vm.StateTree().GetActor(StoragePowerAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -138,7 +138,7 @@ func cheatStorageMarketTotal(t *testing.T, vm *vm.VM, bs bstore.Blockstore) {
|
|||||||
|
|
||||||
sma.Head = c
|
sma.Head = c
|
||||||
|
|
||||||
if err := vm.StateTree().SetActor(StorageMarketAddress, sma); err != nil {
|
if err := vm.StateTree().SetActor(StoragePowerAddress, sma); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,18 @@ import (
|
|||||||
mh "github.com/multiformats/go-multihash"
|
mh "github.com/multiformats/go-multihash"
|
||||||
)
|
)
|
||||||
|
|
||||||
var AccountActorCodeCid cid.Cid
|
var AccountCodeCid cid.Cid
|
||||||
var StorageMarketActorCodeCid cid.Cid
|
var StoragePowerCodeCid cid.Cid
|
||||||
|
var StorageMarketCodeCid cid.Cid
|
||||||
var StorageMinerCodeCid cid.Cid
|
var StorageMinerCodeCid cid.Cid
|
||||||
var MultisigActorCodeCid cid.Cid
|
var MultisigCodeCid cid.Cid
|
||||||
var InitActorCodeCid cid.Cid
|
var InitCodeCid cid.Cid
|
||||||
var PaymentChannelActorCodeCid cid.Cid
|
var PaymentChannelCodeCid cid.Cid
|
||||||
|
|
||||||
var InitActorAddress = mustIDAddress(0)
|
var InitAddress = mustIDAddress(0)
|
||||||
var NetworkAddress = mustIDAddress(1)
|
var NetworkAddress = mustIDAddress(1)
|
||||||
var StorageMarketAddress = mustIDAddress(2)
|
var StoragePowerAddress = mustIDAddress(2)
|
||||||
|
var StorageMarketAddress = mustIDAddress(3) // TODO: missing from spec
|
||||||
var BurntFundsAddress = mustIDAddress(99)
|
var BurntFundsAddress = mustIDAddress(99)
|
||||||
|
|
||||||
func mustIDAddress(i uint64) address.Address {
|
func mustIDAddress(i uint64) address.Address {
|
||||||
@ -37,10 +39,11 @@ func init() {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
AccountActorCodeCid = mustSum("account")
|
AccountCodeCid = mustSum("fil/1/account") // TODO: spec
|
||||||
StorageMarketActorCodeCid = mustSum("smarket")
|
StoragePowerCodeCid = mustSum("fil/1/power")
|
||||||
StorageMinerCodeCid = mustSum("sminer")
|
StorageMarketCodeCid = mustSum("fil/1/market")
|
||||||
MultisigActorCodeCid = mustSum("multisig")
|
StorageMinerCodeCid = mustSum("fil/1/miner")
|
||||||
InitActorCodeCid = mustSum("init")
|
MultisigCodeCid = mustSum("fil/1/multisig")
|
||||||
PaymentChannelActorCodeCid = mustSum("paych")
|
InitCodeCid = mustSum("fil/1/init")
|
||||||
|
PaymentChannelCodeCid = mustSum("fil/1/paych")
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ func TestVMInvokeMethod(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
msg := &types.Message{
|
msg := &types.Message{
|
||||||
To: InitActorAddress,
|
To: InitAddress,
|
||||||
From: from,
|
From: from,
|
||||||
Method: IAMethods.Exec,
|
Method: IAMethods.Exec,
|
||||||
Params: enc,
|
Params: enc,
|
||||||
@ -128,7 +128,7 @@ func TestStorageMarketActorCreateMiner(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
msg := &types.Message{
|
msg := &types.Message{
|
||||||
To: StorageMarketAddress,
|
To: StoragePowerAddress,
|
||||||
From: from,
|
From: from,
|
||||||
Method: SPAMethods.CreateStorageMiner,
|
Method: SPAMethods.CreateStorageMiner,
|
||||||
Params: enc,
|
Params: enc,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -210,7 +210,7 @@ func (h *Harness) CreateActor(t testing.TB, from address.Address,
|
|||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
return h.Apply(t, types.Message{
|
return h.Apply(t, types.Message{
|
||||||
To: actors.InitActorAddress,
|
To: actors.InitAddress,
|
||||||
From: from,
|
From: from,
|
||||||
Method: actors.IAMethods.Exec,
|
Method: actors.IAMethods.Exec,
|
||||||
Params: DumpObject(t,
|
Params: DumpObject(t,
|
||||||
|
778
chain/deals/cbor_gen.go
Normal file
778
chain/deals/cbor_gen.go
Normal file
@ -0,0 +1,778 @@
|
|||||||
|
package deals
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
xerrors "golang.org/x/xerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
/* This file was generated by github.com/whyrusleeping/cbor-gen */
|
||||||
|
|
||||||
|
var _ = xerrors.Errorf
|
||||||
|
|
||||||
|
func (t *AskRequest) MarshalCBOR(w io.Writer) error {
|
||||||
|
if t == nil {
|
||||||
|
_, err := w.Write(cbg.CborNull)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte{129}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Miner (address.Address)
|
||||||
|
if err := t.Miner.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *AskRequest) UnmarshalCBOR(r io.Reader) error {
|
||||||
|
br := cbg.GetPeeker(r)
|
||||||
|
|
||||||
|
maj, extra, err := cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra != 1 {
|
||||||
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Miner (address.Address)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
if err := t.Miner.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *AskResponse) MarshalCBOR(w io.Writer) error {
|
||||||
|
if t == nil {
|
||||||
|
_, err := w.Write(cbg.CborNull)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte{129}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Ask (types.SignedStorageAsk)
|
||||||
|
if err := t.Ask.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *AskResponse) UnmarshalCBOR(r io.Reader) error {
|
||||||
|
br := cbg.GetPeeker(r)
|
||||||
|
|
||||||
|
maj, extra, err := cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra != 1 {
|
||||||
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Ask (types.SignedStorageAsk)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
pb, err := br.PeekByte()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pb == cbg.CborNull[0] {
|
||||||
|
var nbuf [1]byte
|
||||||
|
if _, err := br.Read(nbuf[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Ask = new(types.SignedStorageAsk)
|
||||||
|
if err := t.Ask.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Proposal) MarshalCBOR(w io.Writer) error {
|
||||||
|
if t == nil {
|
||||||
|
_, err := w.Write(cbg.CborNull)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte{129}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.DealProposal (actors.StorageDealProposal)
|
||||||
|
if err := t.DealProposal.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Proposal) UnmarshalCBOR(r io.Reader) error {
|
||||||
|
br := cbg.GetPeeker(r)
|
||||||
|
|
||||||
|
maj, extra, err := cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra != 1 {
|
||||||
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.DealProposal (actors.StorageDealProposal)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
if err := t.DealProposal.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Response) MarshalCBOR(w io.Writer) error {
|
||||||
|
if t == nil {
|
||||||
|
_, err := w.Write(cbg.CborNull)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte{134}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.State (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.State)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Message (string)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.Message)))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte(t.Message)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Proposal (cid.Cid)
|
||||||
|
|
||||||
|
if err := cbg.WriteCid(w, t.Proposal); err != nil {
|
||||||
|
return xerrors.Errorf("failed to write cid field t.Proposal: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.StorageDeal (actors.StorageDeal)
|
||||||
|
if err := t.StorageDeal.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.PublishMessage (cid.Cid)
|
||||||
|
|
||||||
|
if t.PublishMessage == nil {
|
||||||
|
if _, err := w.Write(cbg.CborNull); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := cbg.WriteCid(w, *t.PublishMessage); err != nil {
|
||||||
|
return xerrors.Errorf("failed to write cid field t.PublishMessage: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.CommitMessage (cid.Cid)
|
||||||
|
|
||||||
|
if t.CommitMessage == nil {
|
||||||
|
if _, err := w.Write(cbg.CborNull); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := cbg.WriteCid(w, *t.CommitMessage); err != nil {
|
||||||
|
return xerrors.Errorf("failed to write cid field t.CommitMessage: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Response) UnmarshalCBOR(r io.Reader) error {
|
||||||
|
br := cbg.GetPeeker(r)
|
||||||
|
|
||||||
|
maj, extra, err := cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra != 6 {
|
||||||
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.State (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.State = extra
|
||||||
|
// t.t.Message (string)
|
||||||
|
|
||||||
|
{
|
||||||
|
sval, err := cbg.ReadString(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Message = string(sval)
|
||||||
|
}
|
||||||
|
// t.t.Proposal (cid.Cid)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
c, err := cbg.ReadCid(br)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to read cid field t.Proposal: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Proposal = c
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.StorageDeal (actors.StorageDeal)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
pb, err := br.PeekByte()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pb == cbg.CborNull[0] {
|
||||||
|
var nbuf [1]byte
|
||||||
|
if _, err := br.Read(nbuf[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.StorageDeal = new(actors.StorageDeal)
|
||||||
|
if err := t.StorageDeal.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.PublishMessage (cid.Cid)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
pb, err := br.PeekByte()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pb == cbg.CborNull[0] {
|
||||||
|
var nbuf [1]byte
|
||||||
|
if _, err := br.Read(nbuf[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
c, err := cbg.ReadCid(br)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to read cid field t.PublishMessage: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.PublishMessage = &c
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.CommitMessage (cid.Cid)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
pb, err := br.PeekByte()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pb == cbg.CborNull[0] {
|
||||||
|
var nbuf [1]byte
|
||||||
|
if _, err := br.Read(nbuf[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
c, err := cbg.ReadCid(br)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to read cid field t.CommitMessage: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.CommitMessage = &c
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *SignedResponse) MarshalCBOR(w io.Writer) error {
|
||||||
|
if t == nil {
|
||||||
|
_, err := w.Write(cbg.CborNull)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte{130}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Response (deals.Response)
|
||||||
|
if err := t.Response.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Signature (types.Signature)
|
||||||
|
if err := t.Signature.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *SignedResponse) UnmarshalCBOR(r io.Reader) error {
|
||||||
|
br := cbg.GetPeeker(r)
|
||||||
|
|
||||||
|
maj, extra, err := cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra != 2 {
|
||||||
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Response (deals.Response)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
if err := t.Response.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.Signature (types.Signature)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
pb, err := br.PeekByte()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pb == cbg.CborNull[0] {
|
||||||
|
var nbuf [1]byte
|
||||||
|
if _, err := br.Read(nbuf[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Signature = new(types.Signature)
|
||||||
|
if err := t.Signature.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ClientDealProposal) MarshalCBOR(w io.Writer) error {
|
||||||
|
if t == nil {
|
||||||
|
_, err := w.Write(cbg.CborNull)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte{135}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Data (cid.Cid)
|
||||||
|
|
||||||
|
if err := cbg.WriteCid(w, t.Data); err != nil {
|
||||||
|
return xerrors.Errorf("failed to write cid field t.Data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.TotalPrice (types.BigInt)
|
||||||
|
if err := t.TotalPrice.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.ProposalExpiration (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.ProposalExpiration)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Duration (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Duration)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.ProviderAddress (address.Address)
|
||||||
|
if err := t.ProviderAddress.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Client (address.Address)
|
||||||
|
if err := t.Client.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.MinerID (peer.ID)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.MinerID)))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte(t.MinerID)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ClientDealProposal) UnmarshalCBOR(r io.Reader) error {
|
||||||
|
br := cbg.GetPeeker(r)
|
||||||
|
|
||||||
|
maj, extra, err := cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra != 7 {
|
||||||
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Data (cid.Cid)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
c, err := cbg.ReadCid(br)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to read cid field t.Data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Data = c
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.TotalPrice (types.BigInt)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
if err := t.TotalPrice.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.ProposalExpiration (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.ProposalExpiration = extra
|
||||||
|
// t.t.Duration (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.Duration = extra
|
||||||
|
// t.t.ProviderAddress (address.Address)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
if err := t.ProviderAddress.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.Client (address.Address)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
if err := t.Client.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.MinerID (peer.ID)
|
||||||
|
|
||||||
|
{
|
||||||
|
sval, err := cbg.ReadString(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.MinerID = peer.ID(sval)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ClientDeal) MarshalCBOR(w io.Writer) error {
|
||||||
|
if t == nil {
|
||||||
|
_, err := w.Write(cbg.CborNull)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte{132}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.ProposalCid (cid.Cid)
|
||||||
|
|
||||||
|
if err := cbg.WriteCid(w, t.ProposalCid); err != nil {
|
||||||
|
return xerrors.Errorf("failed to write cid field t.ProposalCid: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Proposal (actors.StorageDealProposal)
|
||||||
|
if err := t.Proposal.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.State (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.State)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Miner (peer.ID)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.Miner)))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte(t.Miner)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ClientDeal) UnmarshalCBOR(r io.Reader) error {
|
||||||
|
br := cbg.GetPeeker(r)
|
||||||
|
|
||||||
|
maj, extra, err := cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra != 4 {
|
||||||
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.ProposalCid (cid.Cid)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
c, err := cbg.ReadCid(br)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to read cid field t.ProposalCid: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ProposalCid = c
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.Proposal (actors.StorageDealProposal)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
if err := t.Proposal.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.State (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.State = extra
|
||||||
|
// t.t.Miner (peer.ID)
|
||||||
|
|
||||||
|
{
|
||||||
|
sval, err := cbg.ReadString(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Miner = peer.ID(sval)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *MinerDeal) MarshalCBOR(w io.Writer) error {
|
||||||
|
if t == nil {
|
||||||
|
_, err := w.Write(cbg.CborNull)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte{135}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Client (peer.ID)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.Client)))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte(t.Client)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Proposal (actors.StorageDealProposal)
|
||||||
|
if err := t.Proposal.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.ProposalCid (cid.Cid)
|
||||||
|
|
||||||
|
if err := cbg.WriteCid(w, t.ProposalCid); err != nil {
|
||||||
|
return xerrors.Errorf("failed to write cid field t.ProposalCid: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.State (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.State)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Ref (cid.Cid)
|
||||||
|
|
||||||
|
if err := cbg.WriteCid(w, t.Ref); err != nil {
|
||||||
|
return xerrors.Errorf("failed to write cid field t.Ref: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.DealID (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.DealID)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.SectorID (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.SectorID)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *MinerDeal) UnmarshalCBOR(r io.Reader) error {
|
||||||
|
br := cbg.GetPeeker(r)
|
||||||
|
|
||||||
|
maj, extra, err := cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra != 7 {
|
||||||
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Client (peer.ID)
|
||||||
|
|
||||||
|
{
|
||||||
|
sval, err := cbg.ReadString(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Client = peer.ID(sval)
|
||||||
|
}
|
||||||
|
// t.t.Proposal (actors.StorageDealProposal)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
if err := t.Proposal.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.ProposalCid (cid.Cid)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
c, err := cbg.ReadCid(br)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to read cid field t.ProposalCid: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ProposalCid = c
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.State (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.State = extra
|
||||||
|
// t.t.Ref (cid.Cid)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
c, err := cbg.ReadCid(br)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to read cid field t.Ref: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Ref = c
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.DealID (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.DealID = extra
|
||||||
|
// t.t.SectorID (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.SectorID = extra
|
||||||
|
return nil
|
||||||
|
}
|
@ -2,12 +2,11 @@ package deals
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math"
|
"github.com/filecoin-project/lotus/node/impl/full"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
"github.com/ipfs/go-datastore/namespace"
|
"github.com/ipfs/go-datastore/namespace"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
logging "github.com/ipfs/go-log"
|
logging "github.com/ipfs/go-log"
|
||||||
"github.com/libp2p/go-libp2p-core/host"
|
"github.com/libp2p/go-libp2p-core/host"
|
||||||
inet "github.com/libp2p/go-libp2p-core/network"
|
inet "github.com/libp2p/go-libp2p-core/network"
|
||||||
@ -18,6 +17,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/lotus/chain/address"
|
"github.com/filecoin-project/lotus/chain/address"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
"github.com/filecoin-project/lotus/chain/wallet"
|
||||||
"github.com/filecoin-project/lotus/lib/cborrpc"
|
"github.com/filecoin-project/lotus/lib/cborrpc"
|
||||||
@ -25,22 +25,11 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/retrieval/discovery"
|
"github.com/filecoin-project/lotus/retrieval/discovery"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
cbor.RegisterCborType(ClientDeal{})
|
|
||||||
cbor.RegisterCborType(actors.PieceInclVoucherData{}) // TODO: USE CBORGEN!
|
|
||||||
cbor.RegisterCborType(types.SignedVoucher{})
|
|
||||||
cbor.RegisterCborType(types.ModVerifyParams{})
|
|
||||||
cbor.RegisterCborType(types.Signature{})
|
|
||||||
cbor.RegisterCborType(actors.PaymentInfo{})
|
|
||||||
cbor.RegisterCborType(api.PaymentInfo{})
|
|
||||||
cbor.RegisterCborType(actors.InclusionProof{})
|
|
||||||
}
|
|
||||||
|
|
||||||
var log = logging.Logger("deals")
|
var log = logging.Logger("deals")
|
||||||
|
|
||||||
type ClientDeal struct {
|
type ClientDeal struct {
|
||||||
ProposalCid cid.Cid
|
ProposalCid cid.Cid
|
||||||
Proposal StorageDealProposal
|
Proposal actors.StorageDealProposal
|
||||||
State api.DealState
|
State api.DealState
|
||||||
Miner peer.ID
|
Miner peer.ID
|
||||||
|
|
||||||
@ -49,15 +38,17 @@ type ClientDeal struct {
|
|||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
sm *stmgr.StateManager
|
sm *stmgr.StateManager
|
||||||
|
chain *store.ChainStore
|
||||||
h host.Host
|
h host.Host
|
||||||
w *wallet.Wallet
|
w *wallet.Wallet
|
||||||
dag dtypes.ClientDAG
|
dag dtypes.ClientDAG
|
||||||
discovery *discovery.Local
|
discovery *discovery.Local
|
||||||
|
mpool full.MpoolAPI
|
||||||
|
|
||||||
deals ClientStateStore
|
deals ClientStateStore
|
||||||
conns map[cid.Cid]inet.Stream
|
conns map[cid.Cid]inet.Stream
|
||||||
|
|
||||||
incoming chan ClientDeal
|
incoming chan *ClientDeal
|
||||||
updated chan clientDealUpdate
|
updated chan clientDealUpdate
|
||||||
|
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
@ -70,18 +61,20 @@ type clientDealUpdate struct {
|
|||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(sm *stmgr.StateManager, h host.Host, w *wallet.Wallet, ds dtypes.MetadataDS, dag dtypes.ClientDAG, discovery *discovery.Local) *Client {
|
func NewClient(sm *stmgr.StateManager, chain *store.ChainStore, h host.Host, w *wallet.Wallet, ds dtypes.MetadataDS, dag dtypes.ClientDAG, discovery *discovery.Local, mpool full.MpoolAPI) *Client {
|
||||||
c := &Client{
|
c := &Client{
|
||||||
sm: sm,
|
sm: sm,
|
||||||
|
chain: chain,
|
||||||
h: h,
|
h: h,
|
||||||
w: w,
|
w: w,
|
||||||
dag: dag,
|
dag: dag,
|
||||||
discovery: discovery,
|
discovery: discovery,
|
||||||
|
mpool: mpool,
|
||||||
|
|
||||||
deals: ClientStateStore{StateStore{ds: namespace.Wrap(ds, datastore.NewKey("/deals/client"))}},
|
deals: ClientStateStore{StateStore{ds: namespace.Wrap(ds, datastore.NewKey("/deals/client"))}},
|
||||||
conns: map[cid.Cid]inet.Stream{},
|
conns: map[cid.Cid]inet.Stream{},
|
||||||
|
|
||||||
incoming: make(chan ClientDeal, 16),
|
incoming: make(chan *ClientDeal, 16),
|
||||||
updated: make(chan clientDealUpdate, 16),
|
updated: make(chan clientDealUpdate, 16),
|
||||||
|
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
@ -108,7 +101,7 @@ func (c *Client) Run(ctx context.Context) {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) onIncoming(deal ClientDeal) {
|
func (c *Client) onIncoming(deal *ClientDeal) {
|
||||||
log.Info("incoming deal")
|
log.Info("incoming deal")
|
||||||
|
|
||||||
if _, ok := c.conns[deal.ProposalCid]; ok {
|
if _, ok := c.conns[deal.ProposalCid]; ok {
|
||||||
@ -166,70 +159,94 @@ func (c *Client) onUpdated(ctx context.Context, update clientDealUpdate) {
|
|||||||
type ClientDealProposal struct {
|
type ClientDealProposal struct {
|
||||||
Data cid.Cid
|
Data cid.Cid
|
||||||
|
|
||||||
TotalPrice types.BigInt
|
TotalPrice types.BigInt
|
||||||
Duration uint64
|
ProposalExpiration uint64
|
||||||
|
Duration uint64
|
||||||
|
|
||||||
Payment actors.PaymentInfo
|
ProviderAddress address.Address
|
||||||
|
Client address.Address
|
||||||
MinerAddress address.Address
|
MinerID peer.ID
|
||||||
ClientAddress address.Address
|
|
||||||
MinerID peer.ID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) VerifyParams(ctx context.Context, data cid.Cid) (*actors.PieceInclVoucherData, error) {
|
func (c *Client) Start(ctx context.Context, p ClientDealProposal) (cid.Cid, error) {
|
||||||
commP, size, err := c.commP(ctx, data)
|
// check market funds
|
||||||
|
clientMarketBalance, err := c.sm.MarketBalance(ctx, p.Client, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return cid.Undef, xerrors.Errorf("getting client market balance failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &actors.PieceInclVoucherData{
|
if clientMarketBalance.Available.LessThan(p.TotalPrice) {
|
||||||
CommP: commP,
|
// TODO: move to a smarter market funds manager
|
||||||
PieceSize: types.NewInt(uint64(size)),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) Start(ctx context.Context, p ClientDealProposal, vd *actors.PieceInclVoucherData) (cid.Cid, error) {
|
smsg, err := c.mpool.MpoolPushMessage(ctx, &types.Message{
|
||||||
proposal := StorageDealProposal{
|
To: actors.StorageMarketAddress,
|
||||||
PieceRef: p.Data,
|
From: p.Client,
|
||||||
SerializationMode: SerializationUnixFs,
|
Value: p.TotalPrice,
|
||||||
CommP: vd.CommP[:],
|
GasPrice: types.NewInt(0),
|
||||||
Size: vd.PieceSize.Uint64(),
|
GasLimit: types.NewInt(1000000),
|
||||||
TotalPrice: p.TotalPrice,
|
Method: actors.SMAMethods.AddBalance,
|
||||||
Duration: p.Duration,
|
})
|
||||||
Payment: p.Payment,
|
if err != nil {
|
||||||
MinerAddress: p.MinerAddress,
|
return cid.Undef, err
|
||||||
ClientAddress: p.ClientAddress,
|
}
|
||||||
|
|
||||||
|
_, r, err := c.sm.WaitForMessage(ctx, smsg.Cid())
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.ExitCode != 0 {
|
||||||
|
return cid.Undef, xerrors.Errorf("adding funds to storage miner market actor failed: exit %d", r.ExitCode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := c.h.NewStream(ctx, p.MinerID, ProtocolID)
|
dataSize, err := c.dataSize(ctx, p.Data)
|
||||||
|
|
||||||
|
proposal := &actors.StorageDealProposal{
|
||||||
|
PieceRef: p.Data.Bytes(),
|
||||||
|
PieceSize: uint64(dataSize),
|
||||||
|
PieceSerialization: actors.SerializationUnixFSv0,
|
||||||
|
Client: p.Client,
|
||||||
|
Provider: p.ProviderAddress,
|
||||||
|
ProposalExpiration: p.ProposalExpiration,
|
||||||
|
Duration: p.Duration,
|
||||||
|
StoragePrice: p.TotalPrice,
|
||||||
|
StorageCollateral: types.NewInt(uint64(dataSize)), // TODO: real calc
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := api.SignWith(ctx, c.w.Sign, p.Client, proposal); err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("signing deal proposal failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
proposalNd, err := cborrpc.AsIpld(proposal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, err
|
return cid.Undef, xerrors.Errorf("getting proposal node failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.sendProposal(s, proposal, p.ClientAddress); err != nil {
|
s, err := c.h.NewStream(ctx, p.MinerID, DealProtocolID)
|
||||||
return cid.Undef, err
|
|
||||||
}
|
|
||||||
|
|
||||||
proposalNd, err := cbor.WrapObject(proposal, math.MaxUint64, -1)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, err
|
s.Reset()
|
||||||
|
return cid.Undef, xerrors.Errorf("connecting to storage provider failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
deal := ClientDeal{
|
if err := cborrpc.WriteCborRPC(s, proposal); err != nil {
|
||||||
|
s.Reset()
|
||||||
|
return cid.Undef, xerrors.Errorf("sending proposal to storage provider failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
deal := &ClientDeal{
|
||||||
ProposalCid: proposalNd.Cid(),
|
ProposalCid: proposalNd.Cid(),
|
||||||
Proposal: proposal,
|
Proposal: *proposal,
|
||||||
State: api.DealUnknown,
|
State: api.DealUnknown,
|
||||||
Miner: p.MinerID,
|
Miner: p.MinerID,
|
||||||
|
|
||||||
s: s,
|
s: s,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: actually care about what happens with the deal after it was accepted
|
|
||||||
c.incoming <- deal
|
c.incoming <- deal
|
||||||
|
|
||||||
// TODO: start tracking after the deal is sealed
|
|
||||||
return deal.ProposalCid, c.discovery.AddPeer(p.Data, discovery.RetrievalPeer{
|
return deal.ProposalCid, c.discovery.AddPeer(p.Data, discovery.RetrievalPeer{
|
||||||
Address: proposal.MinerAddress,
|
Address: proposal.Provider,
|
||||||
ID: deal.Miner,
|
ID: deal.Miner,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,10 @@ package deals
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
|
||||||
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type clientHandlerFunc func(ctx context.Context, deal ClientDeal) error
|
type clientHandlerFunc func(ctx context.Context, deal ClientDeal) error
|
||||||
@ -39,6 +38,39 @@ func (c *Client) new(ctx context.Context, deal ClientDeal) error {
|
|||||||
return xerrors.Errorf("deal wasn't accepted (State=%d)", resp.State)
|
return xerrors.Errorf("deal wasn't accepted (State=%d)", resp.State)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: spec says it's optional
|
||||||
|
pubmsg, err := c.chain.GetMessage(*resp.PublishMessage)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting deal pubsish message: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pw, err := stmgr.GetMinerWorker(ctx, c.sm, nil, deal.Proposal.Provider)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting miner worker failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pubmsg.From != pw {
|
||||||
|
return xerrors.Errorf("deal wasn't published by storage provider: from=%s, provider=%s", pubmsg.From, deal.Proposal.Provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pubmsg.To != actors.StorageMarketAddress {
|
||||||
|
return xerrors.Errorf("deal publish message wasn't set to StorageMarket actor (to=%s)", pubmsg.To)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pubmsg.Method != actors.SMAMethods.PublishStorageDeals {
|
||||||
|
return xerrors.Errorf("deal publish message called incorrect method (method=%s)", pubmsg.Method)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: timeout
|
||||||
|
_, ret, err := c.sm.WaitForMessage(ctx, *resp.PublishMessage)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("waiting for deal publish message: %w", err)
|
||||||
|
}
|
||||||
|
if ret.ExitCode != 0 {
|
||||||
|
return xerrors.Errorf("deal publish failed: exit=%d", ret.ExitCode)
|
||||||
|
}
|
||||||
|
// TODO: persist dealId
|
||||||
|
|
||||||
log.Info("DEAL ACCEPTED!")
|
log.Info("DEAL ACCEPTED!")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -75,13 +107,14 @@ func (c *Client) staged(ctx context.Context, deal ClientDeal) error {
|
|||||||
|
|
||||||
log.Info("DEAL SEALED!")
|
log.Info("DEAL SEALED!")
|
||||||
|
|
||||||
ok, err := sectorbuilder.VerifyPieceInclusionProof(build.SectorSize, deal.Proposal.Size, deal.Proposal.CommP, resp.CommD, resp.PieceInclusionProof.ProofElements)
|
// TODO: want?
|
||||||
|
/*ok, err := sectorbuilder.VerifyPieceInclusionProof(build.SectorSize, deal.Proposal.PieceSize, deal.Proposal.CommP, resp.CommD, resp.PieceInclusionProof.ProofElements)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("verifying piece inclusion proof in staged deal %s: %w", deal.ProposalCid, err)
|
return xerrors.Errorf("verifying piece inclusion proof in staged deal %s: %w", deal.ProposalCid, err)
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return xerrors.Errorf("verifying piece inclusion proof in staged deal %s failed", deal.ProposalCid)
|
return xerrors.Errorf("verifying piece inclusion proof in staged deal %s failed", deal.ProposalCid)
|
||||||
}
|
}*/
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,13 @@ package deals
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
files "github.com/ipfs/go-ipfs-files"
|
files "github.com/ipfs/go-ipfs-files"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
unixfile "github.com/ipfs/go-unixfs/file"
|
unixfile "github.com/ipfs/go-unixfs/file"
|
||||||
inet "github.com/libp2p/go-libp2p-core/network"
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/address"
|
|
||||||
"github.com/filecoin-project/lotus/lib/cborrpc"
|
"github.com/filecoin-project/lotus/lib/cborrpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,68 +28,38 @@ func (c *Client) failDeal(id cid.Cid, cerr error) {
|
|||||||
log.Errorf("deal %s failed: %s", id, cerr)
|
log.Errorf("deal %s failed: %s", id, cerr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) commP(ctx context.Context, data cid.Cid) ([]byte, int64, error) {
|
func (c *Client) dataSize(ctx context.Context, data cid.Cid) (int64, error) {
|
||||||
root, err := c.dag.Get(ctx, data)
|
root, err := c.dag.Get(ctx, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get file root for deal: %s", err)
|
log.Errorf("failed to get file root for deal: %s", err)
|
||||||
return nil, 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := unixfile.NewUnixfsFile(ctx, c.dag, root)
|
n, err := unixfile.NewUnixfsFile(ctx, c.dag, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("cannot open unixfs file: %s", err)
|
log.Errorf("cannot open unixfs file: %s", err)
|
||||||
return nil, 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
uf, ok := n.(files.File)
|
uf, ok := n.(files.File)
|
||||||
if !ok {
|
if !ok {
|
||||||
// TODO: we probably got directory, how should we handle this in unixfs mode?
|
// TODO: we probably got directory, how should we handle this in unixfs mode?
|
||||||
return nil, 0, xerrors.New("unsupported unixfs type")
|
return 0, xerrors.New("unsupported unixfs type")
|
||||||
}
|
}
|
||||||
|
|
||||||
size, err := uf.Size()
|
return uf.Size()
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
commP, err := sectorbuilder.GeneratePieceCommitment(uf, uint64(size))
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return commP[:], size, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) sendProposal(s inet.Stream, proposal StorageDealProposal, from address.Address) error {
|
func (c *Client) readStorageDealResp(deal ClientDeal) (*Response, error) {
|
||||||
log.Info("Sending deal proposal")
|
|
||||||
|
|
||||||
msg, err := cbor.DumpObject(proposal)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
sig, err := c.w.Sign(context.TODO(), from, msg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
signedProposal := &SignedStorageDealProposal{
|
|
||||||
Proposal: proposal,
|
|
||||||
Signature: sig,
|
|
||||||
}
|
|
||||||
|
|
||||||
return cborrpc.WriteCborRPC(s, signedProposal)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) readStorageDealResp(deal ClientDeal) (*StorageDealResponse, error) {
|
|
||||||
s, ok := c.conns[deal.ProposalCid]
|
s, ok := c.conns[deal.ProposalCid]
|
||||||
if !ok {
|
if !ok {
|
||||||
// TODO: Try to re-establish the connection using query protocol
|
// TODO: Try to re-establish the connection using query protocol
|
||||||
return nil, xerrors.Errorf("no connection to miner")
|
return nil, xerrors.Errorf("no connection to miner")
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp SignedStorageDealResponse
|
var resp SignedResponse
|
||||||
if err := cborrpc.ReadCborRPC(s, &resp); err != nil {
|
if err := cborrpc.ReadCborRPC(s, &resp); err != nil {
|
||||||
log.Errorw("failed to read StorageDealResponse message", "error", err)
|
log.Errorw("failed to read Response message", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,313 +0,0 @@
|
|||||||
package deals
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-sectorbuilder/sealing_state"
|
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
"github.com/ipfs/go-merkledag"
|
|
||||||
unixfile "github.com/ipfs/go-unixfs/file"
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
|
||||||
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
|
||||||
"github.com/filecoin-project/lotus/storage/sectorblocks"
|
|
||||||
)
|
|
||||||
|
|
||||||
type minerHandlerFunc func(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error)
|
|
||||||
|
|
||||||
func (h *Handler) handle(ctx context.Context, deal MinerDeal, cb minerHandlerFunc, next api.DealState) {
|
|
||||||
go func() {
|
|
||||||
mut, err := cb(ctx, deal)
|
|
||||||
|
|
||||||
if err == nil && next == api.DealNoUpdate {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case h.updated <- minerDealUpdate{
|
|
||||||
newState: next,
|
|
||||||
id: deal.ProposalCid,
|
|
||||||
err: err,
|
|
||||||
mut: mut,
|
|
||||||
}:
|
|
||||||
case <-h.stop:
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ACCEPTED
|
|
||||||
|
|
||||||
func (h *Handler) checkVoucher(ctx context.Context, deal MinerDeal, voucher *types.SignedVoucher, lane uint64, maxClose uint64, amount types.BigInt) error {
|
|
||||||
err := h.full.PaychVoucherCheckValid(ctx, deal.Proposal.Payment.PayChActor, voucher)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if voucher.Extra == nil {
|
|
||||||
return xerrors.New("voucher.Extra not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
if voucher.Extra.Actor != deal.Proposal.MinerAddress {
|
|
||||||
return xerrors.Errorf("extra params actor didn't match miner address in proposal: '%s' != '%s'", voucher.Extra.Actor, deal.Proposal.MinerAddress)
|
|
||||||
}
|
|
||||||
|
|
||||||
if voucher.Extra.Method != actors.MAMethods.PaymentVerifyInclusion {
|
|
||||||
return xerrors.Errorf("expected extra method %d, got %d", actors.MAMethods.PaymentVerifyInclusion, voucher.Extra.Method)
|
|
||||||
}
|
|
||||||
|
|
||||||
var inclChallenge actors.PieceInclVoucherData
|
|
||||||
if err := cbor.DecodeInto(voucher.Extra.Data, &inclChallenge); err != nil {
|
|
||||||
return xerrors.Errorf("failed to decode storage voucher data for verification: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if inclChallenge.PieceSize.Uint64() != deal.Proposal.Size {
|
|
||||||
return xerrors.Errorf("paych challenge piece size didn't match deal proposal size: %d != %d", inclChallenge.PieceSize.Uint64(), deal.Proposal.Size)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes.Equal(inclChallenge.CommP, deal.Proposal.CommP) {
|
|
||||||
return xerrors.New("paych challenge commP didn't match deal proposal")
|
|
||||||
}
|
|
||||||
|
|
||||||
if voucher.MinCloseHeight > maxClose {
|
|
||||||
return xerrors.Errorf("MinCloseHeight too high (%d), max expected: %d", voucher.MinCloseHeight, maxClose)
|
|
||||||
}
|
|
||||||
|
|
||||||
if voucher.TimeLock > maxClose {
|
|
||||||
return xerrors.Errorf("TimeLock too high (%d), max expected: %d", voucher.TimeLock, maxClose)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(voucher.Merges) > 0 {
|
|
||||||
return xerrors.New("didn't expect any merges")
|
|
||||||
}
|
|
||||||
|
|
||||||
if voucher.Amount.LessThan(amount) {
|
|
||||||
return xerrors.Errorf("not enough funds in the voucher: %s < %s; vl=%d", voucher.Amount, amount, len(deal.Proposal.Payment.Vouchers))
|
|
||||||
}
|
|
||||||
|
|
||||||
if voucher.Lane != lane {
|
|
||||||
return xerrors.Errorf("expected all vouchers on lane %d, found voucher on lane %d", lane, voucher.Lane)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) consumeVouchers(ctx context.Context, deal MinerDeal) error {
|
|
||||||
curHead, err := h.full.ChainHead(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(deal.Proposal.Payment.Vouchers) == 0 {
|
|
||||||
return xerrors.Errorf("no payment vouchers for deal")
|
|
||||||
}
|
|
||||||
|
|
||||||
increment := deal.Proposal.Duration / uint64(len(deal.Proposal.Payment.Vouchers))
|
|
||||||
|
|
||||||
startH := deal.Proposal.Payment.Vouchers[0].TimeLock - increment
|
|
||||||
if startH > curHead.Height()+build.DealVoucherSkewLimit {
|
|
||||||
return xerrors.Errorf("deal starts too far into the future: start=%d; h=%d; max=%d; inc=%d", startH, curHead.Height(), curHead.Height()+build.DealVoucherSkewLimit, increment)
|
|
||||||
}
|
|
||||||
|
|
||||||
vspec := VoucherSpec(deal.Proposal.Duration, deal.Proposal.TotalPrice, startH, nil)
|
|
||||||
|
|
||||||
lane := deal.Proposal.Payment.Vouchers[0].Lane
|
|
||||||
|
|
||||||
for i, voucher := range deal.Proposal.Payment.Vouchers {
|
|
||||||
maxClose := curHead.Height() + (increment * uint64(i+1)) + build.DealVoucherSkewLimit
|
|
||||||
|
|
||||||
if err := h.checkVoucher(ctx, deal, voucher, lane, maxClose, vspec[i].Amount); err != nil {
|
|
||||||
return xerrors.Errorf("validating payment voucher %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
minPrice := types.BigMul(types.BigMul(h.pricePerByteBlock, types.NewInt(deal.Proposal.Size)), types.NewInt(deal.Proposal.Duration))
|
|
||||||
if types.BigCmp(minPrice, deal.Proposal.TotalPrice) > 0 {
|
|
||||||
return xerrors.Errorf("minimum price: %s", minPrice)
|
|
||||||
}
|
|
||||||
|
|
||||||
prevAmt := types.NewInt(0)
|
|
||||||
|
|
||||||
for i, voucher := range deal.Proposal.Payment.Vouchers {
|
|
||||||
delta, err := h.full.PaychVoucherAdd(ctx, deal.Proposal.Payment.PayChActor, voucher, nil, types.BigSub(vspec[i].Amount, prevAmt))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("consuming payment voucher %d: %w", i, err)
|
|
||||||
}
|
|
||||||
prevAmt = types.BigAdd(prevAmt, delta)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) accept(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
|
|
||||||
switch deal.Proposal.SerializationMode {
|
|
||||||
//case SerializationRaw:
|
|
||||||
//case SerializationIPLD:
|
|
||||||
case SerializationUnixFs:
|
|
||||||
default:
|
|
||||||
return nil, xerrors.Errorf("deal proposal with unsupported serialization: %s", deal.Proposal.SerializationMode)
|
|
||||||
}
|
|
||||||
|
|
||||||
if deal.Proposal.Payment.ChannelMessage != nil {
|
|
||||||
log.Info("waiting for channel message to appear on chain")
|
|
||||||
if _, err := h.full.StateWaitMsg(ctx, *deal.Proposal.Payment.ChannelMessage); err != nil {
|
|
||||||
return nil, xerrors.Errorf("waiting for paych message: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := h.consumeVouchers(ctx, deal); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("fetching data for a deal")
|
|
||||||
err := h.sendSignedResponse(StorageDealResponse{
|
|
||||||
State: api.DealAccepted,
|
|
||||||
Message: "",
|
|
||||||
Proposal: deal.ProposalCid,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, merkledag.FetchGraph(ctx, deal.Ref, h.dag)
|
|
||||||
}
|
|
||||||
|
|
||||||
// STAGED
|
|
||||||
|
|
||||||
func (h *Handler) staged(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
|
|
||||||
err := h.sendSignedResponse(StorageDealResponse{
|
|
||||||
State: api.DealStaged,
|
|
||||||
Proposal: deal.ProposalCid,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("Sending deal response failed: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
root, err := h.dag.Get(ctx, deal.Ref)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to get file root for deal: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: abstract this away into ReadSizeCloser + implement different modes
|
|
||||||
n, err := unixfile.NewUnixfsFile(ctx, h.dag, root)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("cannot open unixfs file: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
uf, ok := n.(sectorblocks.UnixfsReader)
|
|
||||||
if !ok {
|
|
||||||
// we probably got directory, unsupported for now
|
|
||||||
return nil, xerrors.Errorf("unsupported unixfs file type")
|
|
||||||
}
|
|
||||||
|
|
||||||
sectorID, err := h.secst.AddUnixfsPiece(deal.Proposal.PieceRef, uf, deal.Proposal.Duration)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("AddPiece failed: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Warnf("New Sector: %d", sectorID)
|
|
||||||
return func(deal *MinerDeal) {
|
|
||||||
deal.SectorID = sectorID
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SEALING
|
|
||||||
|
|
||||||
func getInclusionProof(ref string, status sectorbuilder.SectorSealingStatus) (PieceInclusionProof, error) {
|
|
||||||
for i, p := range status.Pieces {
|
|
||||||
if p.Key == ref {
|
|
||||||
return PieceInclusionProof{
|
|
||||||
Position: uint64(i),
|
|
||||||
ProofElements: p.InclusionProof,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PieceInclusionProof{}, xerrors.Errorf("pieceInclusionProof for %s in sector %d not found", ref, status.SectorID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) waitSealed(ctx context.Context, deal MinerDeal) (sectorbuilder.SectorSealingStatus, error) {
|
|
||||||
status, err := h.secst.WaitSeal(ctx, deal.SectorID)
|
|
||||||
if err != nil {
|
|
||||||
return sectorbuilder.SectorSealingStatus{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch status.State {
|
|
||||||
case sealing_state.Sealed:
|
|
||||||
case sealing_state.Failed:
|
|
||||||
return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("sealing sector %d for deal %s (ref=%s) failed: %s", deal.SectorID, deal.ProposalCid, deal.Ref, status.SealErrorMsg)
|
|
||||||
case sealing_state.Pending:
|
|
||||||
return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("sector status was 'pending' after call to WaitSeal (for sector %d)", deal.SectorID)
|
|
||||||
case sealing_state.Sealing:
|
|
||||||
return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("sector status was 'wait' after call to WaitSeal (for sector %d)", deal.SectorID)
|
|
||||||
default:
|
|
||||||
return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("unknown SealStatusCode: %d", status.SectorID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) sealing(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
|
|
||||||
status, err := h.waitSealed(ctx, deal)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: don't hardcode unixfs
|
|
||||||
ip, err := getInclusionProof(string(sectorblocks.SerializationUnixfs0)+deal.Ref.String(), status)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
proof := &actors.InclusionProof{
|
|
||||||
Sector: deal.SectorID,
|
|
||||||
Proof: ip.ProofElements,
|
|
||||||
}
|
|
||||||
proofB, err := cbor.DumpObject(proof)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// store proofs for channels
|
|
||||||
for i, v := range deal.Proposal.Payment.Vouchers {
|
|
||||||
if v.Extra.Method == actors.MAMethods.PaymentVerifyInclusion {
|
|
||||||
// TODO: Set correct minAmount
|
|
||||||
if _, err := h.full.PaychVoucherAdd(ctx, deal.Proposal.Payment.PayChActor, v, proofB, types.NewInt(0)); err != nil {
|
|
||||||
return nil, xerrors.Errorf("storing payment voucher %d proof: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = h.sendSignedResponse(StorageDealResponse{
|
|
||||||
State: api.DealSealing,
|
|
||||||
Proposal: deal.ProposalCid,
|
|
||||||
PieceInclusionProof: ip,
|
|
||||||
CommD: status.CommD[:],
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("Sending deal response failed: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) complete(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
|
|
||||||
mcid, err := h.commt.WaitCommit(ctx, deal.Proposal.MinerAddress, deal.SectorID)
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("Waiting for sector commitment message: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = h.sendSignedResponse(StorageDealResponse{
|
|
||||||
State: api.DealComplete,
|
|
||||||
Proposal: deal.ProposalCid,
|
|
||||||
|
|
||||||
SectorCommitMessage: &mcid,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("Sending deal response failed: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
@ -2,43 +2,40 @@ package deals
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
datastore "github.com/ipfs/go-datastore"
|
datastore "github.com/ipfs/go-datastore"
|
||||||
"github.com/ipfs/go-datastore/namespace"
|
"github.com/ipfs/go-datastore/namespace"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
inet "github.com/libp2p/go-libp2p-core/network"
|
inet "github.com/libp2p/go-libp2p-core/network"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/lotus/chain/address"
|
"github.com/filecoin-project/lotus/chain/address"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/lib/cborrpc"
|
||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
"github.com/filecoin-project/lotus/storage/commitment"
|
"github.com/filecoin-project/lotus/storage/commitment"
|
||||||
"github.com/filecoin-project/lotus/storage/sectorblocks"
|
"github.com/filecoin-project/lotus/storage/sectorblocks"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
cbor.RegisterCborType(MinerDeal{})
|
|
||||||
}
|
|
||||||
|
|
||||||
type MinerDeal struct {
|
type MinerDeal struct {
|
||||||
Client peer.ID
|
Client peer.ID
|
||||||
Proposal StorageDealProposal
|
Proposal actors.StorageDealProposal
|
||||||
ProposalCid cid.Cid
|
ProposalCid cid.Cid
|
||||||
State api.DealState
|
State api.DealState
|
||||||
|
|
||||||
Ref cid.Cid
|
Ref cid.Cid
|
||||||
|
|
||||||
|
DealID uint64
|
||||||
SectorID uint64 // Set when State >= DealStaged
|
SectorID uint64 // Set when State >= DealStaged
|
||||||
|
|
||||||
s inet.Stream
|
s inet.Stream
|
||||||
}
|
}
|
||||||
|
|
||||||
type Handler struct {
|
type Provider struct {
|
||||||
pricePerByteBlock types.BigInt // how much we want for storing one byte for one block
|
pricePerByteBlock types.BigInt // how much we want for storing one byte for one block
|
||||||
minPieceSize uint64
|
minPieceSize uint64
|
||||||
|
|
||||||
@ -73,7 +70,7 @@ type minerDealUpdate struct {
|
|||||||
mut func(*MinerDeal)
|
mut func(*MinerDeal)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(ds dtypes.MetadataDS, secst *sectorblocks.SectorBlocks, commt *commitment.Tracker, dag dtypes.StagingDAG, fullNode api.FullNode) (*Handler, error) {
|
func NewProvider(ds dtypes.MetadataDS, secst *sectorblocks.SectorBlocks, commt *commitment.Tracker, dag dtypes.StagingDAG, fullNode api.FullNode) (*Provider, error) {
|
||||||
addr, err := ds.Get(datastore.NewKey("miner-address"))
|
addr, err := ds.Get(datastore.NewKey("miner-address"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -83,7 +80,7 @@ func NewHandler(ds dtypes.MetadataDS, secst *sectorblocks.SectorBlocks, commt *c
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
h := &Handler{
|
h := &Provider{
|
||||||
secst: secst,
|
secst: secst,
|
||||||
commt: commt,
|
commt: commt,
|
||||||
dag: dag,
|
dag: dag,
|
||||||
@ -120,40 +117,40 @@ func NewHandler(ds dtypes.MetadataDS, secst *sectorblocks.SectorBlocks, commt *c
|
|||||||
return h, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) Run(ctx context.Context) {
|
func (p *Provider) Run(ctx context.Context) {
|
||||||
// TODO: restore state
|
// TODO: restore state
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer log.Warn("quitting deal handler loop")
|
defer log.Warn("quitting deal provider loop")
|
||||||
defer close(h.stopped)
|
defer close(p.stopped)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case deal := <-h.incoming: // DealAccepted
|
case deal := <-p.incoming: // DealAccepted
|
||||||
h.onIncoming(deal)
|
p.onIncoming(deal)
|
||||||
case update := <-h.updated: // DealStaged
|
case update := <-p.updated: // DealStaged
|
||||||
h.onUpdated(ctx, update)
|
p.onUpdated(ctx, update)
|
||||||
case <-h.stop:
|
case <-p.stop:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) onIncoming(deal MinerDeal) {
|
func (p *Provider) onIncoming(deal MinerDeal) {
|
||||||
log.Info("incoming deal")
|
log.Info("incoming deal")
|
||||||
|
|
||||||
h.conns[deal.ProposalCid] = deal.s
|
p.conns[deal.ProposalCid] = deal.s
|
||||||
|
|
||||||
if err := h.deals.Begin(deal.ProposalCid, deal); err != nil {
|
if err := p.deals.Begin(deal.ProposalCid, &deal); err != nil {
|
||||||
// This can happen when client re-sends proposal
|
// This can happen when client re-sends proposal
|
||||||
h.failDeal(deal.ProposalCid, err)
|
p.failDeal(deal.ProposalCid, err)
|
||||||
log.Errorf("deal tracking failed: %s", err)
|
log.Errorf("deal tracking failed: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
h.updated <- minerDealUpdate{
|
p.updated <- minerDealUpdate{
|
||||||
newState: api.DealAccepted,
|
newState: api.DealAccepted,
|
||||||
id: deal.ProposalCid,
|
id: deal.ProposalCid,
|
||||||
err: nil,
|
err: nil,
|
||||||
@ -161,15 +158,15 @@ func (h *Handler) onIncoming(deal MinerDeal) {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) onUpdated(ctx context.Context, update minerDealUpdate) {
|
func (p *Provider) onUpdated(ctx context.Context, update minerDealUpdate) {
|
||||||
log.Infof("Deal %s updated state to %d", update.id, update.newState)
|
log.Infof("Deal %s updated state to %d", update.id, update.newState)
|
||||||
if update.err != nil {
|
if update.err != nil {
|
||||||
log.Errorf("deal %s failed: %s", update.id, update.err)
|
log.Errorf("deal %s (newSt: %d) failed: %s", update.id, update.newState, update.err)
|
||||||
h.failDeal(update.id, update.err)
|
p.failDeal(update.id, update.err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var deal MinerDeal
|
var deal MinerDeal
|
||||||
err := h.deals.MutateMiner(update.id, func(d *MinerDeal) error {
|
err := p.deals.MutateMiner(update.id, func(d *MinerDeal) error {
|
||||||
d.State = update.newState
|
d.State = update.newState
|
||||||
if update.mut != nil {
|
if update.mut != nil {
|
||||||
update.mut(d)
|
update.mut(d)
|
||||||
@ -178,30 +175,29 @@ func (h *Handler) onUpdated(ctx context.Context, update minerDealUpdate) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.failDeal(update.id, err)
|
p.failDeal(update.id, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch update.newState {
|
switch update.newState {
|
||||||
case api.DealAccepted:
|
case api.DealAccepted:
|
||||||
h.handle(ctx, deal, h.accept, api.DealStaged)
|
p.handle(ctx, deal, p.accept, api.DealStaged)
|
||||||
case api.DealStaged:
|
case api.DealStaged:
|
||||||
h.handle(ctx, deal, h.staged, api.DealSealing)
|
p.handle(ctx, deal, p.staged, api.DealSealing)
|
||||||
case api.DealSealing:
|
case api.DealSealing:
|
||||||
h.handle(ctx, deal, h.sealing, api.DealComplete)
|
p.handle(ctx, deal, p.sealing, api.DealComplete)
|
||||||
case api.DealComplete:
|
case api.DealComplete:
|
||||||
h.handle(ctx, deal, h.complete, api.DealNoUpdate)
|
p.handle(ctx, deal, p.complete, api.DealNoUpdate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) newDeal(s inet.Stream, proposal StorageDealProposal) (MinerDeal, error) {
|
func (p *Provider) newDeal(s inet.Stream, proposal actors.StorageDealProposal) (MinerDeal, error) {
|
||||||
// TODO: Review: Not signed?
|
proposalNd, err := cborrpc.AsIpld(&proposal)
|
||||||
proposalNd, err := cbor.WrapObject(proposal, math.MaxUint64, -1)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return MinerDeal{}, err
|
return MinerDeal{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ref, err := cid.Parse(proposal.PieceRef)
|
ref, err := cid.Cast(proposal.PieceRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return MinerDeal{}, err
|
return MinerDeal{}, err
|
||||||
}
|
}
|
||||||
@ -218,27 +214,27 @@ func (h *Handler) newDeal(s inet.Stream, proposal StorageDealProposal) (MinerDea
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) HandleStream(s inet.Stream) {
|
func (p *Provider) HandleStream(s inet.Stream) {
|
||||||
log.Info("Handling storage deal proposal!")
|
log.Info("Handling storage deal proposal!")
|
||||||
|
|
||||||
proposal, err := h.readProposal(s)
|
proposal, err := p.readProposal(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
s.Close()
|
s.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
deal, err := h.newDeal(s, proposal.Proposal)
|
deal, err := p.newDeal(s, proposal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
s.Close()
|
s.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.incoming <- deal
|
p.incoming <- deal
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) Stop() {
|
func (p *Provider) Stop() {
|
||||||
close(h.stop)
|
close(p.stop)
|
||||||
<-h.stopped
|
<-p.stopped
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package deals
|
package deals
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -9,49 +10,48 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/lib/cborrpc"
|
"github.com/filecoin-project/lotus/lib/cborrpc"
|
||||||
datastore "github.com/ipfs/go-datastore"
|
datastore "github.com/ipfs/go-datastore"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
inet "github.com/libp2p/go-libp2p-core/network"
|
inet "github.com/libp2p/go-libp2p-core/network"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handler) SetPrice(p types.BigInt, ttlsecs int64) error {
|
func (p *Provider) SetPrice(price types.BigInt, ttlsecs int64) error {
|
||||||
h.askLk.Lock()
|
p.askLk.Lock()
|
||||||
defer h.askLk.Unlock()
|
defer p.askLk.Unlock()
|
||||||
|
|
||||||
var seqno uint64
|
var seqno uint64
|
||||||
if h.ask != nil {
|
if p.ask != nil {
|
||||||
seqno = h.ask.Ask.SeqNo + 1
|
seqno = p.ask.Ask.SeqNo + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
ask := &types.StorageAsk{
|
ask := &types.StorageAsk{
|
||||||
Price: p,
|
Price: price,
|
||||||
Timestamp: now,
|
Timestamp: uint64(now),
|
||||||
Expiry: now + ttlsecs,
|
Expiry: uint64(now + ttlsecs),
|
||||||
Miner: h.actor,
|
Miner: p.actor,
|
||||||
SeqNo: seqno,
|
SeqNo: seqno,
|
||||||
MinPieceSize: h.minPieceSize,
|
MinPieceSize: p.minPieceSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
ssa, err := h.signAsk(ask)
|
ssa, err := p.signAsk(ask)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return h.saveAsk(ssa)
|
return p.saveAsk(ssa)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) getAsk(m address.Address) *types.SignedStorageAsk {
|
func (p *Provider) getAsk(m address.Address) *types.SignedStorageAsk {
|
||||||
h.askLk.Lock()
|
p.askLk.Lock()
|
||||||
defer h.askLk.Unlock()
|
defer p.askLk.Unlock()
|
||||||
if m != h.actor {
|
if m != p.actor {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return h.ask
|
return p.ask
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) HandleAskStream(s inet.Stream) {
|
func (p *Provider) HandleAskStream(s inet.Stream) {
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
var ar AskRequest
|
var ar AskRequest
|
||||||
if err := cborrpc.ReadCborRPC(s, &ar); err != nil {
|
if err := cborrpc.ReadCborRPC(s, &ar); err != nil {
|
||||||
@ -59,7 +59,7 @@ func (h *Handler) HandleAskStream(s inet.Stream) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := h.processAskRequest(&ar)
|
resp := p.processAskRequest(&ar)
|
||||||
|
|
||||||
if err := cborrpc.WriteCborRPC(s, resp); err != nil {
|
if err := cborrpc.WriteCborRPC(s, resp); err != nil {
|
||||||
log.Errorf("failed to write ask response: %s", err)
|
log.Errorf("failed to write ask response: %s", err)
|
||||||
@ -67,19 +67,19 @@ func (h *Handler) HandleAskStream(s inet.Stream) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) processAskRequest(ar *AskRequest) *AskResponse {
|
func (p *Provider) processAskRequest(ar *AskRequest) *AskResponse {
|
||||||
return &AskResponse{
|
return &AskResponse{
|
||||||
Ask: h.getAsk(ar.Miner),
|
Ask: p.getAsk(ar.Miner),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var bestAskKey = datastore.NewKey("latest-ask")
|
var bestAskKey = datastore.NewKey("latest-ask")
|
||||||
|
|
||||||
func (h *Handler) tryLoadAsk() error {
|
func (p *Provider) tryLoadAsk() error {
|
||||||
h.askLk.Lock()
|
p.askLk.Lock()
|
||||||
defer h.askLk.Unlock()
|
defer p.askLk.Unlock()
|
||||||
|
|
||||||
err := h.loadAsk()
|
err := p.loadAsk()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if xerrors.Is(err, datastore.ErrNotFound) {
|
if xerrors.Is(err, datastore.ErrNotFound) {
|
||||||
log.Warn("no previous ask found, miner will not accept deals until a price is set")
|
log.Warn("no previous ask found, miner will not accept deals until a price is set")
|
||||||
@ -91,33 +91,33 @@ func (h *Handler) tryLoadAsk() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) loadAsk() error {
|
func (p *Provider) loadAsk() error {
|
||||||
askb, err := h.ds.Get(datastore.NewKey("latest-ask"))
|
askb, err := p.ds.Get(datastore.NewKey("latest-ask"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to load most recent ask from disk: %w", err)
|
return xerrors.Errorf("failed to load most recent ask from disk: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ssa types.SignedStorageAsk
|
var ssa types.SignedStorageAsk
|
||||||
if err := cbor.DecodeInto(askb, &ssa); err != nil {
|
if err := cborrpc.ReadCborRPC(bytes.NewReader(askb), &ssa); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
h.ask = &ssa
|
p.ask = &ssa
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) signAsk(a *types.StorageAsk) (*types.SignedStorageAsk, error) {
|
func (p *Provider) signAsk(a *types.StorageAsk) (*types.SignedStorageAsk, error) {
|
||||||
b, err := cbor.DumpObject(a)
|
b, err := cborrpc.Dump(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
worker, err := h.getWorker(h.actor)
|
worker, err := p.getWorker(p.actor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to get worker to sign ask: %w", err)
|
return nil, xerrors.Errorf("failed to get worker to sign ask: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sig, err := h.full.WalletSign(context.TODO(), worker, b)
|
sig, err := p.full.WalletSign(context.TODO(), worker, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -128,29 +128,29 @@ func (h *Handler) signAsk(a *types.StorageAsk) (*types.SignedStorageAsk, error)
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) saveAsk(a *types.SignedStorageAsk) error {
|
func (p *Provider) saveAsk(a *types.SignedStorageAsk) error {
|
||||||
b, err := cbor.DumpObject(a)
|
b, err := cborrpc.Dump(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.ds.Put(bestAskKey, b); err != nil {
|
if err := p.ds.Put(bestAskKey, b); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
h.ask = a
|
p.ask = a
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) checkAskSignature(ask *types.SignedStorageAsk) error {
|
func (c *Client) checkAskSignature(ask *types.SignedStorageAsk) error {
|
||||||
tss := c.sm.ChainStore().GetHeaviestTipSet().ParentState()
|
tss := c.sm.ChainStore().GetHeaviestTipSet().ParentState()
|
||||||
|
|
||||||
w, err := stmgr.GetMinerWorker(context.TODO(), c.sm, tss, ask.Ask.Miner)
|
w, err := stmgr.GetMinerWorkerRaw(context.TODO(), c.sm, tss, ask.Ask.Miner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to get worker for miner in ask", err)
|
return xerrors.Errorf("failed to get worker for miner in ask", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sigb, err := cbor.DumpObject(ask.Ask)
|
sigb, err := cborrpc.Dump(ask.Ask)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to re-serialize ask")
|
return xerrors.Errorf("failed to re-serialize ask")
|
||||||
}
|
}
|
305
chain/deals/provider_states.go
Normal file
305
chain/deals/provider_states.go
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
package deals
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-sectorbuilder/sealing_state"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
"github.com/ipfs/go-merkledag"
|
||||||
|
unixfile "github.com/ipfs/go-unixfs/file"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/address"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
||||||
|
"github.com/filecoin-project/lotus/storage/sectorblocks"
|
||||||
|
)
|
||||||
|
|
||||||
|
type providerHandlerFunc func(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error)
|
||||||
|
|
||||||
|
func (p *Provider) handle(ctx context.Context, deal MinerDeal, cb providerHandlerFunc, next api.DealState) {
|
||||||
|
go func() {
|
||||||
|
mut, err := cb(ctx, deal)
|
||||||
|
|
||||||
|
if err == nil && next == api.DealNoUpdate {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p.updated <- minerDealUpdate{
|
||||||
|
newState: next,
|
||||||
|
id: deal.ProposalCid,
|
||||||
|
err: err,
|
||||||
|
mut: mut,
|
||||||
|
}:
|
||||||
|
case <-p.stop:
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ACCEPTED
|
||||||
|
|
||||||
|
func (p *Provider) addMarketFunds(ctx context.Context, worker address.Address, deal MinerDeal) error {
|
||||||
|
log.Info("Adding market funds for storage collateral")
|
||||||
|
smsg, err := p.full.MpoolPushMessage(ctx, &types.Message{
|
||||||
|
To: actors.StorageMarketAddress,
|
||||||
|
From: worker,
|
||||||
|
Value: deal.Proposal.StorageCollateral,
|
||||||
|
GasPrice: types.NewInt(0),
|
||||||
|
GasLimit: types.NewInt(1000000),
|
||||||
|
Method: actors.SMAMethods.AddBalance,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := p.full.StateWaitMsg(ctx, smsg.Cid())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Receipt.ExitCode != 0 {
|
||||||
|
return xerrors.Errorf("adding funds to storage miner market actor failed: exit %d", r.Receipt.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) accept(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
|
||||||
|
switch deal.Proposal.PieceSerialization {
|
||||||
|
//case SerializationRaw:
|
||||||
|
//case SerializationIPLD:
|
||||||
|
case actors.SerializationUnixFSv0:
|
||||||
|
default:
|
||||||
|
return nil, xerrors.Errorf("deal proposal with unsupported serialization: %s", deal.Proposal.PieceSerialization)
|
||||||
|
}
|
||||||
|
|
||||||
|
head, err := p.full.ChainHead(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if head.Height() >= deal.Proposal.ProposalExpiration {
|
||||||
|
return nil, xerrors.Errorf("deal proposal already expired")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check StorageCollateral
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
minPrice := types.BigMul(p.ask.Ask.Price, types.BigMul(types.NewInt(deal.Proposal.Duration), types.NewInt(deal.Proposal.PieceSize)))
|
||||||
|
if deal.Proposal.StoragePrice.LessThan(minPrice) {
|
||||||
|
return nil, xerrors.Errorf("storage price less than asking price: %s < %s", deal.Proposal.StoragePrice, minPrice)
|
||||||
|
}
|
||||||
|
|
||||||
|
if deal.Proposal.PieceSize < p.ask.Ask.MinPieceSize {
|
||||||
|
return nil, xerrors.Errorf("piece size less than minimum required size: %d < %d", deal.Proposal.PieceSize, p.ask.Ask.MinPieceSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check market funds
|
||||||
|
clientMarketBalance, err := p.full.StateMarketBalance(ctx, deal.Proposal.Client, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("getting client market balance failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This doesn't guarantee that the client won't withdraw / lock those funds
|
||||||
|
// but it's a decent first filter
|
||||||
|
if clientMarketBalance.Available.LessThan(deal.Proposal.StoragePrice) {
|
||||||
|
return nil, xerrors.New("clientMarketBalance.Available too small")
|
||||||
|
}
|
||||||
|
|
||||||
|
waddr, err := p.full.StateMinerWorker(ctx, deal.Proposal.Provider, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
providerMarketBalance, err := p.full.StateMarketBalance(ctx, waddr, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("getting provider market balance failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this needs to be atomic
|
||||||
|
if providerMarketBalance.Available.LessThan(deal.Proposal.StorageCollateral) {
|
||||||
|
if err := p.addMarketFunds(ctx, waddr, deal); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("publishing deal")
|
||||||
|
|
||||||
|
storageDeal := actors.StorageDeal{
|
||||||
|
Proposal: deal.Proposal,
|
||||||
|
}
|
||||||
|
if err := api.SignWith(ctx, p.full.WalletSign, waddr, &storageDeal); err != nil {
|
||||||
|
return nil, xerrors.Errorf("signing storage deal failed: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
params, err := actors.SerializeParams(&actors.PublishStorageDealsParams{
|
||||||
|
Deals: []actors.StorageDeal{storageDeal},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("serializing PublishStorageDeals params failed: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: We may want this to happen after fetching data
|
||||||
|
smsg, err := p.full.MpoolPushMessage(ctx, &types.Message{
|
||||||
|
To: actors.StorageMarketAddress,
|
||||||
|
From: waddr,
|
||||||
|
Value: types.NewInt(0),
|
||||||
|
GasPrice: types.NewInt(0),
|
||||||
|
GasLimit: types.NewInt(1000000),
|
||||||
|
Method: actors.SMAMethods.PublishStorageDeals,
|
||||||
|
Params: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r, err := p.full.StateWaitMsg(ctx, smsg.Cid())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r.Receipt.ExitCode != 0 {
|
||||||
|
return nil, xerrors.Errorf("publishing deal failed: exit %d", r.Receipt.ExitCode)
|
||||||
|
}
|
||||||
|
var resp actors.PublishStorageDealResponse
|
||||||
|
if err := resp.UnmarshalCBOR(bytes.NewReader(r.Receipt.Return)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(resp.DealIDs) != 1 {
|
||||||
|
return nil, xerrors.Errorf("got unexpected number of DealIDs from")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("fetching data for a deal")
|
||||||
|
mcid := smsg.Cid()
|
||||||
|
err = p.sendSignedResponse(&Response{
|
||||||
|
State: api.DealAccepted,
|
||||||
|
Message: "",
|
||||||
|
Proposal: deal.ProposalCid,
|
||||||
|
PublishMessage: &mcid,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(deal *MinerDeal) {
|
||||||
|
deal.DealID = resp.DealIDs[0]
|
||||||
|
}, merkledag.FetchGraph(ctx, deal.Ref, p.dag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// STAGED
|
||||||
|
|
||||||
|
func (p *Provider) staged(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
|
||||||
|
err := p.sendSignedResponse(&Response{
|
||||||
|
State: api.DealStaged,
|
||||||
|
Proposal: deal.ProposalCid,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Sending deal response failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
root, err := p.dag.Get(ctx, deal.Ref)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to get file root for deal: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: abstract this away into ReadSizeCloser + implement different modes
|
||||||
|
n, err := unixfile.NewUnixfsFile(ctx, p.dag, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("cannot open unixfs file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
uf, ok := n.(sectorblocks.UnixfsReader)
|
||||||
|
if !ok {
|
||||||
|
// we probably got directory, unsupported for now
|
||||||
|
return nil, xerrors.Errorf("unsupported unixfs file type")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: uf.Size() is user input, not trusted
|
||||||
|
// This won't be useful / here after we migrate to putting CARs into sectors
|
||||||
|
size, err := uf.Size()
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("getting unixfs file size: %w", err)
|
||||||
|
}
|
||||||
|
if uint64(size) != deal.Proposal.PieceSize {
|
||||||
|
return nil, xerrors.Errorf("deal.Proposal.PieceSize didn't match unixfs file size")
|
||||||
|
}
|
||||||
|
|
||||||
|
pcid, err := cid.Cast(deal.Proposal.PieceRef)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sectorID, err := p.secst.AddUnixfsPiece(pcid, uf, deal.DealID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("AddPiece failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warnf("New Sector: %d", sectorID)
|
||||||
|
return func(deal *MinerDeal) {
|
||||||
|
deal.SectorID = sectorID
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEALING
|
||||||
|
|
||||||
|
func (p *Provider) waitSealed(ctx context.Context, deal MinerDeal) (sectorbuilder.SectorSealingStatus, error) {
|
||||||
|
status, err := p.secst.WaitSeal(ctx, deal.SectorID)
|
||||||
|
if err != nil {
|
||||||
|
return sectorbuilder.SectorSealingStatus{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch status.State {
|
||||||
|
case sealing_state.Sealed:
|
||||||
|
case sealing_state.Failed:
|
||||||
|
return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("sealing sector %d for deal %s (ref=%s) failed: %s", deal.SectorID, deal.ProposalCid, deal.Ref, status.SealErrorMsg)
|
||||||
|
case sealing_state.Pending:
|
||||||
|
return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("sector status was 'pending' after call to WaitSeal (for sector %d)", deal.SectorID)
|
||||||
|
case sealing_state.Sealing:
|
||||||
|
return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("sector status was 'wait' after call to WaitSeal (for sector %d)", deal.SectorID)
|
||||||
|
default:
|
||||||
|
return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("unknown SealStatusCode: %d", status.SectorID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) sealing(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
|
||||||
|
err := p.sendSignedResponse(&Response{
|
||||||
|
State: api.DealSealing,
|
||||||
|
Proposal: deal.ProposalCid,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Sending deal response failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = p.waitSealed(ctx, deal)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// TODO: Spec doesn't say anything about inclusion proofs anywhere
|
||||||
|
// Not sure what mechanisms prevents miner from storing data that isn't
|
||||||
|
// clients' data
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) complete(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
|
||||||
|
// TODO: Add dealID to commtracker (probably before sealing)
|
||||||
|
mcid, err := p.commt.WaitCommit(ctx, deal.Proposal.Provider, deal.SectorID)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Waiting for sector commitment message: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = p.sendSignedResponse(&Response{
|
||||||
|
State: api.DealComplete,
|
||||||
|
Proposal: deal.ProposalCid,
|
||||||
|
|
||||||
|
CommitMessage: &mcid,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Sending deal response failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
@ -12,13 +12,12 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/lib/cborrpc"
|
"github.com/filecoin-project/lotus/lib/cborrpc"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
inet "github.com/libp2p/go-libp2p-core/network"
|
inet "github.com/libp2p/go-libp2p-core/network"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handler) failDeal(id cid.Cid, cerr error) {
|
func (p *Provider) failDeal(id cid.Cid, cerr error) {
|
||||||
if err := h.deals.End(id); err != nil {
|
if err := p.deals.End(id); err != nil {
|
||||||
log.Warnf("deals.End: %s", err)
|
log.Warnf("deals.End: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,16 +28,16 @@ func (h *Handler) failDeal(id cid.Cid, cerr error) {
|
|||||||
|
|
||||||
log.Errorf("deal %s failed: %s", id, cerr)
|
log.Errorf("deal %s failed: %s", id, cerr)
|
||||||
|
|
||||||
err := h.sendSignedResponse(StorageDealResponse{
|
err := p.sendSignedResponse(&Response{
|
||||||
State: api.DealFailed,
|
State: api.DealFailed,
|
||||||
Message: cerr.Error(),
|
Message: cerr.Error(),
|
||||||
Proposal: id,
|
Proposal: id,
|
||||||
})
|
})
|
||||||
|
|
||||||
s, ok := h.conns[id]
|
s, ok := p.conns[id]
|
||||||
if ok {
|
if ok {
|
||||||
_ = s.Reset()
|
_ = s.Reset()
|
||||||
delete(h.conns, id)
|
delete(p.conns, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -46,46 +45,50 @@ func (h *Handler) failDeal(id cid.Cid, cerr error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) readProposal(s inet.Stream) (proposal SignedStorageDealProposal, err error) {
|
func (p *Provider) readProposal(s inet.Stream) (proposal actors.StorageDealProposal, err error) {
|
||||||
if err := cborrpc.ReadCborRPC(s, &proposal); err != nil {
|
if err := cborrpc.ReadCborRPC(s, &proposal); err != nil {
|
||||||
log.Errorw("failed to read proposal message", "error", err)
|
log.Errorw("failed to read proposal message", "error", err)
|
||||||
return SignedStorageDealProposal{}, err
|
return proposal, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := proposal.Verify(); err != nil {
|
||||||
|
return proposal, xerrors.Errorf("verifying StorageDealProposal: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Validate proposal maybe
|
// TODO: Validate proposal maybe
|
||||||
// (and signature, obviously)
|
// (and signature, obviously)
|
||||||
|
|
||||||
if proposal.Proposal.MinerAddress != h.actor {
|
if proposal.Provider != p.actor {
|
||||||
log.Errorf("proposal with wrong MinerAddress: %s", proposal.Proposal.MinerAddress)
|
log.Errorf("proposal with wrong ProviderAddress: %s", proposal.Provider)
|
||||||
return SignedStorageDealProposal{}, err
|
return proposal, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) sendSignedResponse(resp StorageDealResponse) error {
|
func (p *Provider) sendSignedResponse(resp *Response) error {
|
||||||
s, ok := h.conns[resp.Proposal]
|
s, ok := p.conns[resp.Proposal]
|
||||||
if !ok {
|
if !ok {
|
||||||
return xerrors.New("couldn't send response: not connected")
|
return xerrors.New("couldn't send response: not connected")
|
||||||
}
|
}
|
||||||
|
|
||||||
msg, err := cbor.DumpObject(&resp)
|
msg, err := cborrpc.Dump(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("serializing response: %w", err)
|
return xerrors.Errorf("serializing response: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
worker, err := h.getWorker(h.actor)
|
worker, err := p.getWorker(p.actor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sig, err := h.full.WalletSign(context.TODO(), worker, msg)
|
sig, err := p.full.WalletSign(context.TODO(), worker, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to sign response message: %w", err)
|
return xerrors.Errorf("failed to sign response message: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
signedResponse := SignedStorageDealResponse{
|
signedResponse := &SignedResponse{
|
||||||
Response: resp,
|
Response: *resp,
|
||||||
Signature: sig,
|
Signature: sig,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,18 +96,18 @@ func (h *Handler) sendSignedResponse(resp StorageDealResponse) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// Assume client disconnected
|
// Assume client disconnected
|
||||||
s.Close()
|
s.Close()
|
||||||
delete(h.conns, resp.Proposal)
|
delete(p.conns, resp.Proposal)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) getWorker(miner address.Address) (address.Address, error) {
|
func (p *Provider) getWorker(miner address.Address) (address.Address, error) {
|
||||||
getworker := &types.Message{
|
getworker := &types.Message{
|
||||||
To: miner,
|
To: miner,
|
||||||
From: miner,
|
From: miner,
|
||||||
Method: actors.MAMethods.GetWorkerAddr,
|
Method: actors.MAMethods.GetWorkerAddr,
|
||||||
}
|
}
|
||||||
r, err := h.full.StateCall(context.TODO(), getworker, nil)
|
r, err := p.full.StateCall(context.TODO(), getworker, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return address.Undef, xerrors.Errorf("getting worker address: %w", err)
|
return address.Undef, xerrors.Errorf("getting worker address: %w", err)
|
||||||
}
|
}
|
@ -1,10 +1,11 @@
|
|||||||
package deals
|
package deals
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/filecoin-project/lotus/lib/cborrpc"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
"github.com/ipfs/go-datastore/query"
|
"github.com/ipfs/go-datastore/query"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ func (st *StateStore) Begin(i cid.Cid, state interface{}) error {
|
|||||||
return xerrors.Errorf("Already tracking state for %s", i)
|
return xerrors.Errorf("Already tracking state for %s", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := cbor.DumpObject(state)
|
b, err := cborrpc.Dump(state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -75,17 +76,17 @@ func (st *MinerStateStore) MutateMiner(i cid.Cid, mutator func(*MinerDeal) error
|
|||||||
|
|
||||||
func minerMutator(m func(*MinerDeal) error) func([]byte) ([]byte, error) {
|
func minerMutator(m func(*MinerDeal) error) func([]byte) ([]byte, error) {
|
||||||
return func(in []byte) ([]byte, error) {
|
return func(in []byte) ([]byte, error) {
|
||||||
var deal MinerDeal
|
deal := new(MinerDeal)
|
||||||
err := cbor.DecodeInto(in, &deal)
|
err := cborrpc.ReadCborRPC(bytes.NewReader(in), deal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := m(&deal); err != nil {
|
if err := m(deal); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return cbor.DumpObject(deal)
|
return cborrpc.Dump(deal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,17 +100,17 @@ func (st *ClientStateStore) MutateClient(i cid.Cid, mutator func(*ClientDeal) er
|
|||||||
|
|
||||||
func clientMutator(m func(*ClientDeal) error) func([]byte) ([]byte, error) {
|
func clientMutator(m func(*ClientDeal) error) func([]byte) ([]byte, error) {
|
||||||
return func(in []byte) ([]byte, error) {
|
return func(in []byte) ([]byte, error) {
|
||||||
var deal ClientDeal
|
deal := new(ClientDeal)
|
||||||
err := cbor.DecodeInto(in, &deal)
|
err := cborrpc.ReadCborRPC(bytes.NewReader(in), deal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := m(&deal); err != nil {
|
if err := m(deal); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return cbor.DumpObject(deal)
|
return cborrpc.Dump(deal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +130,7 @@ func (st *ClientStateStore) ListClient() ([]ClientDeal, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var deal ClientDeal
|
var deal ClientDeal
|
||||||
err := cbor.DecodeInto(res.Value, &deal)
|
err := cborrpc.ReadCborRPC(bytes.NewReader(res.Value), &deal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -2,83 +2,37 @@ package deals
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/ipfs/go-cid"
|
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/lotus/chain/address"
|
"github.com/filecoin-project/lotus/chain/address"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
const DealProtocolID = "/fil/storage/mk/1.0.0"
|
||||||
cbor.RegisterCborType(StorageDealProposal{})
|
|
||||||
cbor.RegisterCborType(SignedStorageDealProposal{})
|
|
||||||
|
|
||||||
cbor.RegisterCborType(PieceInclusionProof{})
|
|
||||||
|
|
||||||
cbor.RegisterCborType(StorageDealResponse{})
|
|
||||||
cbor.RegisterCborType(SignedStorageDealResponse{})
|
|
||||||
|
|
||||||
cbor.RegisterCborType(AskRequest{})
|
|
||||||
cbor.RegisterCborType(AskResponse{})
|
|
||||||
}
|
|
||||||
|
|
||||||
const ProtocolID = "/fil/storage/mk/1.0.0"
|
|
||||||
const AskProtocolID = "/fil/storage/ask/1.0.0"
|
const AskProtocolID = "/fil/storage/ask/1.0.0"
|
||||||
|
|
||||||
type SerializationMode string
|
type Proposal struct {
|
||||||
|
DealProposal actors.StorageDealProposal
|
||||||
const (
|
|
||||||
SerializationUnixFs = "UnixFs"
|
|
||||||
SerializationRaw = "Raw"
|
|
||||||
SerializationIPLD = "IPLD"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StorageDealProposal struct {
|
|
||||||
PieceRef cid.Cid // TODO: port to spec
|
|
||||||
SerializationMode SerializationMode
|
|
||||||
CommP []byte
|
|
||||||
|
|
||||||
Size uint64
|
|
||||||
TotalPrice types.BigInt
|
|
||||||
Duration uint64
|
|
||||||
|
|
||||||
Payment actors.PaymentInfo
|
|
||||||
|
|
||||||
MinerAddress address.Address
|
|
||||||
ClientAddress address.Address
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SignedStorageDealProposal struct {
|
type Response struct {
|
||||||
Proposal StorageDealProposal
|
|
||||||
|
|
||||||
Signature *types.Signature
|
|
||||||
}
|
|
||||||
|
|
||||||
// response
|
|
||||||
|
|
||||||
type PieceInclusionProof struct {
|
|
||||||
Position uint64
|
|
||||||
ProofElements []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type StorageDealResponse struct {
|
|
||||||
State api.DealState
|
State api.DealState
|
||||||
|
|
||||||
// DealRejected / DealAccepted / DealFailed / DealStaged
|
// DealProposalRejected
|
||||||
Message string
|
Message string
|
||||||
Proposal cid.Cid
|
Proposal cid.Cid
|
||||||
|
|
||||||
// DealSealing
|
// DealAccepted
|
||||||
PieceInclusionProof PieceInclusionProof
|
StorageDeal *actors.StorageDeal
|
||||||
CommD []byte // TODO: not in spec
|
PublishMessage *cid.Cid
|
||||||
|
|
||||||
// DealComplete
|
// DealComplete
|
||||||
SectorCommitMessage *cid.Cid
|
CommitMessage *cid.Cid
|
||||||
}
|
}
|
||||||
|
|
||||||
type SignedStorageDealResponse struct {
|
// TODO: Do we actually need this to be signed?
|
||||||
Response StorageDealResponse
|
type SignedResponse struct {
|
||||||
|
Response Response
|
||||||
|
|
||||||
Signature *types.Signature
|
Signature *types.Signature
|
||||||
}
|
}
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
package deals
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
func VoucherSpec(blocksDuration uint64, price types.BigInt, start uint64, extra *types.ModVerifyParams) []api.VoucherSpec {
|
|
||||||
nVouchers := blocksDuration / build.MinDealVoucherIncrement
|
|
||||||
if nVouchers < 1 {
|
|
||||||
nVouchers = 1
|
|
||||||
}
|
|
||||||
if nVouchers > build.MaxVouchersPerDeal {
|
|
||||||
nVouchers = build.MaxVouchersPerDeal
|
|
||||||
}
|
|
||||||
|
|
||||||
hIncrements := blocksDuration / nVouchers
|
|
||||||
vouchers := make([]api.VoucherSpec, nVouchers)
|
|
||||||
|
|
||||||
for i := uint64(0); i < nVouchers; i++ {
|
|
||||||
vouchers[i] = api.VoucherSpec{
|
|
||||||
Amount: types.BigDiv(types.BigMul(price, types.NewInt(i+1)), types.NewInt(nVouchers)),
|
|
||||||
TimeLock: start + (hIncrements * (i + 1)),
|
|
||||||
MinClose: start + (hIncrements * (i + 1)),
|
|
||||||
Extra: extra,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return vouchers
|
|
||||||
}
|
|
@ -206,7 +206,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
|
|||||||
|
|
||||||
st := pts.ParentState()
|
st := pts.ParentState()
|
||||||
|
|
||||||
worker, err := stmgr.GetMinerWorker(ctx, cg.sm, st, m)
|
worker, err := stmgr.GetMinerWorkerRaw(ctx, cg.sm, st, m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -385,7 +385,7 @@ func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, ts *t
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mca mca) StateMinerWorker(ctx context.Context, maddr address.Address, ts *types.TipSet) (address.Address, error) {
|
func (mca mca) StateMinerWorker(ctx context.Context, maddr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||||
return stmgr.GetMinerWorker(ctx, mca.sm, ts.ParentState(), maddr)
|
return stmgr.GetMinerWorkerRaw(ctx, mca.sm, ts.ParentState(), maddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*types.Signature, error) {
|
func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*types.Signature, error) {
|
||||||
|
@ -27,7 +27,7 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
|
|||||||
|
|
||||||
height := parents.Height() + uint64(len(tickets))
|
height := parents.Height() + uint64(len(tickets))
|
||||||
|
|
||||||
worker, err := stmgr.GetMinerWorker(ctx, sm, st, miner)
|
worker, err := stmgr.GetMinerWorkerRaw(ctx, sm, st, miner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to get miner worker: %w", err)
|
return nil, xerrors.Errorf("failed to get miner worker: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
amt "github.com/filecoin-project/go-amt-ipld"
|
amt "github.com/filecoin-project/go-amt-ipld"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
"github.com/ipfs/go-datastore"
|
||||||
|
hamt "github.com/ipfs/go-hamt-ipld"
|
||||||
|
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||||
|
peer "github.com/libp2p/go-libp2p-peer"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
actors "github.com/filecoin-project/lotus/chain/actors"
|
actors "github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/lotus/chain/address"
|
"github.com/filecoin-project/lotus/chain/address"
|
||||||
@ -12,14 +20,6 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
|
||||||
"github.com/ipfs/go-datastore"
|
|
||||||
hamt "github.com/ipfs/go-hamt-ipld"
|
|
||||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
|
||||||
peer "github.com/libp2p/go-libp2p-peer"
|
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type GenesisBootstrap struct {
|
type GenesisBootstrap struct {
|
||||||
@ -56,7 +56,7 @@ func SetupInitActor(bs bstore.Blockstore, addrs []address.Address) (*types.Actor
|
|||||||
}
|
}
|
||||||
|
|
||||||
act := &types.Actor{
|
act := &types.Actor{
|
||||||
Code: actors.InitActorCodeCid,
|
Code: actors.InitCodeCid,
|
||||||
Head: statecid,
|
Head: statecid,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,10 +85,19 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types
|
|||||||
return nil, xerrors.Errorf("setup init actor: %w", err)
|
return nil, xerrors.Errorf("setup init actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := state.SetActor(actors.InitActorAddress, initact); err != nil {
|
if err := state.SetActor(actors.InitAddress, initact); err != nil {
|
||||||
return nil, xerrors.Errorf("set init actor: %w", err)
|
return nil, xerrors.Errorf("set init actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spact, err := SetupStoragePowerActor(bs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("setup storage market actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := state.SetActor(actors.StoragePowerAddress, spact); err != nil {
|
||||||
|
return nil, xerrors.Errorf("set storage market actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
smact, err := SetupStorageMarketActor(bs)
|
smact, err := SetupStorageMarketActor(bs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("setup storage market actor: %w", err)
|
return nil, xerrors.Errorf("setup storage market actor: %w", err)
|
||||||
@ -104,7 +113,7 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = state.SetActor(actors.NetworkAddress, &types.Actor{
|
err = state.SetActor(actors.NetworkAddress, &types.Actor{
|
||||||
Code: actors.AccountActorCodeCid,
|
Code: actors.AccountCodeCid,
|
||||||
Balance: netAmt,
|
Balance: netAmt,
|
||||||
Head: emptyobject,
|
Head: emptyobject,
|
||||||
})
|
})
|
||||||
@ -113,7 +122,7 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = state.SetActor(actors.BurntFundsAddress, &types.Actor{
|
err = state.SetActor(actors.BurntFundsAddress, &types.Actor{
|
||||||
Code: actors.AccountActorCodeCid,
|
Code: actors.AccountCodeCid,
|
||||||
Balance: types.NewInt(0),
|
Balance: types.NewInt(0),
|
||||||
Head: emptyobject,
|
Head: emptyobject,
|
||||||
})
|
})
|
||||||
@ -123,7 +132,7 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types
|
|||||||
|
|
||||||
for a, v := range actmap {
|
for a, v := range actmap {
|
||||||
err = state.SetActor(a, &types.Actor{
|
err = state.SetActor(a, &types.Actor{
|
||||||
Code: actors.AccountActorCodeCid,
|
Code: actors.AccountCodeCid,
|
||||||
Balance: v,
|
Balance: v,
|
||||||
Head: emptyobject,
|
Head: emptyobject,
|
||||||
})
|
})
|
||||||
@ -135,7 +144,7 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types
|
|||||||
return state, nil
|
return state, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) {
|
func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||||
cst := hamt.CSTFromBstore(bs)
|
cst := hamt.CSTFromBstore(bs)
|
||||||
nd := hamt.NewNode(cst)
|
nd := hamt.NewNode(cst)
|
||||||
emptyhamt, err := cst.Put(context.TODO(), nd)
|
emptyhamt, err := cst.Put(context.TODO(), nd)
|
||||||
@ -154,7 +163,41 @@ func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &types.Actor{
|
return &types.Actor{
|
||||||
Code: actors.StorageMarketActorCodeCid,
|
Code: actors.StoragePowerCodeCid,
|
||||||
|
Head: stcid,
|
||||||
|
Nonce: 0,
|
||||||
|
Balance: types.NewInt(0),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||||
|
cst := hamt.CSTFromBstore(bs)
|
||||||
|
nd := hamt.NewNode(cst)
|
||||||
|
emptyHAMT, err := cst.Put(context.TODO(), nd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blks := amt.WrapBlockstore(bs)
|
||||||
|
|
||||||
|
emptyAMT, err := amt.FromArray(blks, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("amt build failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sms := &actors.StorageMarketState{
|
||||||
|
Balances: emptyHAMT,
|
||||||
|
Deals: emptyAMT,
|
||||||
|
NextDealID: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
stcid, err := cst.Put(context.TODO(), sms)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Actor{
|
||||||
|
Code: actors.StorageMarketCodeCid,
|
||||||
Head: stcid,
|
Head: stcid,
|
||||||
Nonce: 0,
|
Nonce: 0,
|
||||||
Balance: types.NewInt(0),
|
Balance: types.NewInt(0),
|
||||||
@ -202,7 +245,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
|||||||
|
|
||||||
// TODO: hardcoding 7000000 here is a little fragile, it changes any
|
// TODO: hardcoding 7000000 here is a little fragile, it changes any
|
||||||
// time anyone changes the initial account allocations
|
// time anyone changes the initial account allocations
|
||||||
rval, err := doExecValue(ctx, vm, actors.StorageMarketAddress, owner, types.FromFil(6500), actors.SPAMethods.CreateStorageMiner, params)
|
rval, err := doExecValue(ctx, vm, actors.StoragePowerAddress, owner, types.FromFil(6500), actors.SPAMethods.CreateStorageMiner, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err)
|
return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err)
|
||||||
}
|
}
|
||||||
@ -216,7 +259,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
|||||||
|
|
||||||
params = mustEnc(&actors.UpdateStorageParams{Delta: types.NewInt(5000)})
|
params = mustEnc(&actors.UpdateStorageParams{Delta: types.NewInt(5000)})
|
||||||
|
|
||||||
_, err = doExec(ctx, vm, actors.StorageMarketAddress, maddr, actors.SPAMethods.UpdateStorage, params)
|
_, err = doExec(ctx, vm, actors.StoragePowerAddress, maddr, actors.SPAMethods.UpdateStorage, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("failed to update total storage: %w", err)
|
return cid.Undef, xerrors.Errorf("failed to update total storage: %w", err)
|
||||||
}
|
}
|
||||||
@ -333,7 +376,7 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B
|
|||||||
}
|
}
|
||||||
|
|
||||||
b := &types.BlockHeader{
|
b := &types.BlockHeader{
|
||||||
Miner: actors.InitActorAddress,
|
Miner: actors.InitAddress,
|
||||||
Tickets: []*types.Ticket{genesisticket},
|
Tickets: []*types.Ticket{genesisticket},
|
||||||
ElectionProof: []byte("the Genesis block"),
|
ElectionProof: []byte("the Genesis block"),
|
||||||
Parents: []cid.Cid{},
|
Parents: []cid.Cid{},
|
||||||
|
@ -68,7 +68,7 @@ func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTree) lookupID(addr address.Address) (address.Address, error) {
|
func (st *StateTree) lookupID(addr address.Address) (address.Address, error) {
|
||||||
act, err := st.GetActor(actors.InitActorAddress)
|
act, err := st.GetActor(actors.InitAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return address.Undef, xerrors.Errorf("getting init actor: %w", err)
|
return address.Undef, xerrors.Errorf("getting init actor: %w", err)
|
||||||
}
|
}
|
||||||
@ -143,7 +143,7 @@ func (st *StateTree) Snapshot() error {
|
|||||||
|
|
||||||
func (st *StateTree) RegisterNewAddress(addr address.Address, act *types.Actor) (address.Address, error) {
|
func (st *StateTree) RegisterNewAddress(addr address.Address, act *types.Actor) (address.Address, error) {
|
||||||
var out address.Address
|
var out address.Address
|
||||||
err := st.MutateActor(actors.InitActorAddress, func(initact *types.Actor) error {
|
err := st.MutateActor(actors.InitAddress, func(initact *types.Actor) error {
|
||||||
var ias actors.InitActorState
|
var ias actors.InitActorState
|
||||||
if err := st.Store.Get(context.TODO(), initact.Head, &ias); err != nil {
|
if err := st.Store.Get(context.TODO(), initact.Head, &ias); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -27,7 +27,7 @@ func BenchmarkStateTreeSet(b *testing.B) {
|
|||||||
err = st.SetActor(a, &types.Actor{
|
err = st.SetActor(a, &types.Actor{
|
||||||
Balance: types.NewInt(1258812523),
|
Balance: types.NewInt(1258812523),
|
||||||
Code: actors.StorageMinerCodeCid,
|
Code: actors.StorageMinerCodeCid,
|
||||||
Head: actors.AccountActorCodeCid,
|
Head: actors.AccountCodeCid,
|
||||||
Nonce: uint64(i),
|
Nonce: uint64(i),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -54,7 +54,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) {
|
|||||||
err = st.SetActor(a, &types.Actor{
|
err = st.SetActor(a, &types.Actor{
|
||||||
Balance: types.NewInt(1258812523),
|
Balance: types.NewInt(1258812523),
|
||||||
Code: actors.StorageMinerCodeCid,
|
Code: actors.StorageMinerCodeCid,
|
||||||
Head: actors.AccountActorCodeCid,
|
Head: actors.AccountCodeCid,
|
||||||
Nonce: uint64(i),
|
Nonce: uint64(i),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -80,7 +80,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) {
|
|||||||
err = st.SetActor(a, &types.Actor{
|
err = st.SetActor(a, &types.Actor{
|
||||||
Balance: types.NewInt(1258812523 + uint64(i)),
|
Balance: types.NewInt(1258812523 + uint64(i)),
|
||||||
Code: actors.StorageMinerCodeCid,
|
Code: actors.StorageMinerCodeCid,
|
||||||
Head: actors.AccountActorCodeCid,
|
Head: actors.AccountCodeCid,
|
||||||
Nonce: uint64(i),
|
Nonce: uint64(i),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -123,7 +123,7 @@ func TestSetCache(t *testing.T) {
|
|||||||
act := &types.Actor{
|
act := &types.Actor{
|
||||||
Balance: types.NewInt(0),
|
Balance: types.NewInt(0),
|
||||||
Code: actors.StorageMinerCodeCid,
|
Code: actors.StorageMinerCodeCid,
|
||||||
Head: actors.AccountActorCodeCid,
|
Head: actors.AccountCodeCid,
|
||||||
Nonce: 0,
|
Nonce: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,3 +462,17 @@ func (sm *StateManager) ListAllActors(ctx context.Context, ts *types.TipSet) ([]
|
|||||||
|
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (actors.StorageParticipantBalance, error) {
|
||||||
|
var state actors.StorageMarketState
|
||||||
|
if _, err := sm.LoadActorState(ctx, actors.StorageMarketAddress, &state, ts); err != nil {
|
||||||
|
return actors.StorageParticipantBalance{}, err
|
||||||
|
}
|
||||||
|
cst := hamt.CSTFromBstore(sm.ChainStore().Blockstore())
|
||||||
|
b, _, err := actors.GetMarketBalances(ctx, cst, state.Balances, addr)
|
||||||
|
if err != nil {
|
||||||
|
return actors.StorageParticipantBalance{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b[0], nil
|
||||||
|
}
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetMinerWorker(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) {
|
func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) {
|
||||||
recp, err := sm.CallRaw(ctx, &types.Message{
|
recp, err := sm.CallRaw(ctx, &types.Message{
|
||||||
To: maddr,
|
To: maddr,
|
||||||
From: maddr,
|
From: maddr,
|
||||||
@ -80,7 +80,7 @@ func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr add
|
|||||||
}
|
}
|
||||||
ret, err := sm.Call(ctx, &types.Message{
|
ret, err := sm.Call(ctx, &types.Message{
|
||||||
From: maddr,
|
From: maddr,
|
||||||
To: actors.StorageMarketAddress,
|
To: actors.StoragePowerAddress,
|
||||||
Method: actors.SPAMethods.PowerLookup,
|
Method: actors.SPAMethods.PowerLookup,
|
||||||
Params: enc,
|
Params: enc,
|
||||||
}, ts)
|
}, ts)
|
||||||
@ -95,8 +95,8 @@ func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr add
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret, err := sm.Call(ctx, &types.Message{
|
ret, err := sm.Call(ctx, &types.Message{
|
||||||
From: actors.StorageMarketAddress,
|
From: actors.StoragePowerAddress,
|
||||||
To: actors.StorageMarketAddress,
|
To: actors.StoragePowerAddress,
|
||||||
Method: actors.SPAMethods.GetTotalStorage,
|
Method: actors.SPAMethods.GetTotalStorage,
|
||||||
}, ts)
|
}, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -118,7 +118,7 @@ func GetMinerPeerID(ctx context.Context, sm *StateManager, ts *types.TipSet, mad
|
|||||||
Method: actors.MAMethods.GetPeerID,
|
Method: actors.MAMethods.GetPeerID,
|
||||||
}, ts)
|
}, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", xerrors.Errorf("callRaw failed: %w", err)
|
return "", xerrors.Errorf("call failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if recp.ExitCode != 0 {
|
if recp.ExitCode != 0 {
|
||||||
@ -128,6 +128,23 @@ func GetMinerPeerID(ctx context.Context, sm *StateManager, ts *types.TipSet, mad
|
|||||||
return peer.IDFromBytes(recp.Return)
|
return peer.IDFromBytes(recp.Return)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetMinerWorker(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (address.Address, error) {
|
||||||
|
recp, err := sm.Call(ctx, &types.Message{
|
||||||
|
To: maddr,
|
||||||
|
From: maddr,
|
||||||
|
Method: actors.MAMethods.GetWorkerAddr,
|
||||||
|
}, ts)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, xerrors.Errorf("call failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if recp.ExitCode != 0 {
|
||||||
|
return address.Undef, xerrors.Errorf("getting miner peer ID failed (exit code %d)", recp.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return address.NewFromBytes(recp.Return)
|
||||||
|
}
|
||||||
|
|
||||||
func GetMinerProvingPeriodEnd(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (uint64, error) {
|
func GetMinerProvingPeriodEnd(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (uint64, error) {
|
||||||
var mas actors.StorageMinerActorState
|
var mas actors.StorageMinerActorState
|
||||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||||
|
@ -23,8 +23,8 @@ func (cs *ChainStore) Weight(ctx context.Context, ts *types.TipSet) (types.BigIn
|
|||||||
// >>> wFunction(totalPowerAtTipset(ts)) * 2^8 <<< + (wFunction(totalPowerAtTipset(ts)) * len(ts.blocks) * wRatio_num * 2^8) / (e * wRatio_den)
|
// >>> wFunction(totalPowerAtTipset(ts)) * 2^8 <<< + (wFunction(totalPowerAtTipset(ts)) * len(ts.blocks) * wRatio_num * 2^8) / (e * wRatio_den)
|
||||||
|
|
||||||
ret, err := cs.call(ctx, &types.Message{
|
ret, err := cs.call(ctx, &types.Message{
|
||||||
From: actors.StorageMarketAddress,
|
From: actors.StoragePowerAddress,
|
||||||
To: actors.StorageMarketAddress,
|
To: actors.StoragePowerAddress,
|
||||||
Method: actors.SPAMethods.GetTotalStorage,
|
Method: actors.SPAMethods.GetTotalStorage,
|
||||||
}, ts)
|
}, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -398,7 +398,7 @@ func (syncer *Syncer) minerIsValid(ctx context.Context, maddr address.Address, b
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret, err := syncer.sm.Call(ctx, &types.Message{
|
ret, err := syncer.sm.Call(ctx, &types.Message{
|
||||||
To: actors.StorageMarketAddress,
|
To: actors.StoragePowerAddress,
|
||||||
From: maddr,
|
From: maddr,
|
||||||
Method: actors.SPAMethods.IsMiner,
|
Method: actors.SPAMethods.IsMiner,
|
||||||
Params: enc,
|
Params: enc,
|
||||||
@ -482,9 +482,9 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
|||||||
return xerrors.Errorf("minerIsValid failed: %w", err)
|
return xerrors.Errorf("minerIsValid failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
waddr, err := stmgr.GetMinerWorker(ctx, syncer.sm, stateroot, h.Miner)
|
waddr, err := stmgr.GetMinerWorkerRaw(ctx, syncer.sm, stateroot, h.Miner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("GetMinerWorker failed: %w", err)
|
return xerrors.Errorf("GetMinerWorkerRaw failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.CheckBlockSignature(ctx, waddr); err != nil {
|
if err := h.CheckBlockSignature(ctx, waddr); err != nil {
|
||||||
|
@ -19,7 +19,7 @@ type StorageAsk struct {
|
|||||||
Price BigInt
|
Price BigInt
|
||||||
MinPieceSize uint64
|
MinPieceSize uint64
|
||||||
Miner address.Address
|
Miner address.Address
|
||||||
Timestamp int64
|
Timestamp uint64
|
||||||
Expiry int64
|
Expiry uint64
|
||||||
SeqNo uint64
|
SeqNo uint64
|
||||||
}
|
}
|
||||||
|
@ -1272,3 +1272,201 @@ func (t *BlockMsg) UnmarshalCBOR(r io.Reader) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *SignedStorageAsk) MarshalCBOR(w io.Writer) error {
|
||||||
|
if t == nil {
|
||||||
|
_, err := w.Write(cbg.CborNull)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte{130}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Ask (types.StorageAsk)
|
||||||
|
if err := t.Ask.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Signature (types.Signature)
|
||||||
|
if err := t.Signature.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *SignedStorageAsk) UnmarshalCBOR(r io.Reader) error {
|
||||||
|
br := cbg.GetPeeker(r)
|
||||||
|
|
||||||
|
maj, extra, err := cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra != 2 {
|
||||||
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Ask (types.StorageAsk)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
pb, err := br.PeekByte()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pb == cbg.CborNull[0] {
|
||||||
|
var nbuf [1]byte
|
||||||
|
if _, err := br.Read(nbuf[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Ask = new(StorageAsk)
|
||||||
|
if err := t.Ask.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.Signature (types.Signature)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
pb, err := br.PeekByte()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pb == cbg.CborNull[0] {
|
||||||
|
var nbuf [1]byte
|
||||||
|
if _, err := br.Read(nbuf[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Signature = new(Signature)
|
||||||
|
if err := t.Signature.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *StorageAsk) MarshalCBOR(w io.Writer) error {
|
||||||
|
if t == nil {
|
||||||
|
_, err := w.Write(cbg.CborNull)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte{134}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Price (types.BigInt)
|
||||||
|
if err := t.Price.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.MinPieceSize (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.MinPieceSize)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Miner (address.Address)
|
||||||
|
if err := t.Miner.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Timestamp (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Timestamp)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Expiry (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Expiry)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.SeqNo (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.SeqNo)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *StorageAsk) UnmarshalCBOR(r io.Reader) error {
|
||||||
|
br := cbg.GetPeeker(r)
|
||||||
|
|
||||||
|
maj, extra, err := cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra != 6 {
|
||||||
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Price (types.BigInt)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
if err := t.Price.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.MinPieceSize (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.MinPieceSize = extra
|
||||||
|
// t.t.Miner (address.Address)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
if err := t.Miner.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.Timestamp (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.Timestamp = extra
|
||||||
|
// t.t.Expiry (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.Expiry = extra
|
||||||
|
// t.t.SeqNo (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.SeqNo = extra
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -29,11 +29,12 @@ func newInvoker() *invoker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add builtInCode using: register(cid, singleton)
|
// add builtInCode using: register(cid, singleton)
|
||||||
inv.register(actors.InitActorCodeCid, actors.InitActor{}, actors.InitActorState{})
|
inv.register(actors.InitCodeCid, actors.InitActor{}, actors.InitActorState{})
|
||||||
inv.register(actors.StorageMarketActorCodeCid, actors.StoragePowerActor{}, actors.StoragePowerState{})
|
inv.register(actors.StoragePowerCodeCid, actors.StoragePowerActor{}, actors.StoragePowerState{})
|
||||||
|
inv.register(actors.StorageMarketCodeCid, actors.StorageMarketActor{}, actors.StorageMarketState{})
|
||||||
inv.register(actors.StorageMinerCodeCid, actors.StorageMinerActor{}, actors.StorageMinerActorState{})
|
inv.register(actors.StorageMinerCodeCid, actors.StorageMinerActor{}, actors.StorageMinerActorState{})
|
||||||
inv.register(actors.MultisigActorCodeCid, actors.MultiSigActor{}, actors.MultiSigActorState{})
|
inv.register(actors.MultisigCodeCid, actors.MultiSigActor{}, actors.MultiSigActorState{})
|
||||||
inv.register(actors.PaymentChannelActorCodeCid, actors.PaymentChannelActor{}, actors.PaymentChannelActorState{})
|
inv.register(actors.PaymentChannelCodeCid, actors.PaymentChannelActor{}, actors.PaymentChannelActorState{})
|
||||||
|
|
||||||
return inv
|
return inv
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ func NewBLSAccountActor(st *state.StateTree, addr address.Address) (*types.Actor
|
|||||||
}
|
}
|
||||||
|
|
||||||
nact := &types.Actor{
|
nact := &types.Actor{
|
||||||
Code: actors.AccountActorCodeCid,
|
Code: actors.AccountCodeCid,
|
||||||
Balance: types.NewInt(0),
|
Balance: types.NewInt(0),
|
||||||
Head: c,
|
Head: c,
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ func NewBLSAccountActor(st *state.StateTree, addr address.Address) (*types.Actor
|
|||||||
|
|
||||||
func NewSecp256k1AccountActor(st *state.StateTree, addr address.Address) (*types.Actor, aerrors.ActorError) {
|
func NewSecp256k1AccountActor(st *state.StateTree, addr address.Address) (*types.Actor, aerrors.ActorError) {
|
||||||
nact := &types.Actor{
|
nact := &types.Actor{
|
||||||
Code: actors.AccountActorCodeCid,
|
Code: actors.AccountCodeCid,
|
||||||
Balance: types.NewInt(0),
|
Balance: types.NewInt(0),
|
||||||
Head: EmptyObjectCid,
|
Head: EmptyObjectCid,
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,7 @@ func (vmc *VMContext) ChargeGas(amount uint64) aerrors.ActorError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (vmc *VMContext) StateTree() (types.StateTree, aerrors.ActorError) {
|
func (vmc *VMContext) StateTree() (types.StateTree, aerrors.ActorError) {
|
||||||
if vmc.msg.To != actors.InitActorAddress {
|
if vmc.msg.To != actors.InitAddress {
|
||||||
return nil, aerrors.Escalate(fmt.Errorf("only init actor can access state tree directly"), "invalid use of StateTree")
|
return nil, aerrors.Escalate(fmt.Errorf("only init actor can access state tree directly"), "invalid use of StateTree")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ func ResolveToKeyAddr(state types.StateTree, cst *hamt.CborIpldStore, addr addre
|
|||||||
return address.Undef, aerrors.Newf(1, "failed to find actor: %s", addr)
|
return address.Undef, aerrors.Newf(1, "failed to find actor: %s", addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if act.Code != actors.AccountActorCodeCid {
|
if act.Code != actors.AccountCodeCid {
|
||||||
return address.Undef, aerrors.New(1, "address was not for an account actor")
|
return address.Undef, aerrors.New(1, "address was not for an account actor")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ var createMinerCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
msg := &types.Message{
|
msg := &types.Message{
|
||||||
To: actors.StorageMarketAddress,
|
To: actors.StoragePowerAddress,
|
||||||
From: addr,
|
From: addr,
|
||||||
Method: actors.SPAMethods.CreateStorageMiner,
|
Method: actors.SPAMethods.CreateStorageMiner,
|
||||||
Params: params,
|
Params: params,
|
||||||
|
@ -303,7 +303,7 @@ func createStorageMiner(ctx context.Context, api api.FullNode, peerid peer.ID, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
createStorageMinerMsg := &types.Message{
|
createStorageMinerMsg := &types.Message{
|
||||||
To: actors.StorageMarketAddress,
|
To: actors.StoragePowerAddress,
|
||||||
From: owner,
|
From: owner,
|
||||||
Value: collateral,
|
Value: collateral,
|
||||||
|
|
||||||
|
37
gen/main.go
37
gen/main.go
@ -4,9 +4,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
|
||||||
gen "github.com/whyrusleeping/cbor-gen"
|
gen "github.com/whyrusleeping/cbor-gen"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/deals"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -22,6 +24,8 @@ func main() {
|
|||||||
types.Actor{},
|
types.Actor{},
|
||||||
types.MessageReceipt{},
|
types.MessageReceipt{},
|
||||||
types.BlockMsg{},
|
types.BlockMsg{},
|
||||||
|
types.SignedStorageAsk{},
|
||||||
|
types.StorageAsk{},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@ -46,11 +50,9 @@ func main() {
|
|||||||
actors.AccountActorState{},
|
actors.AccountActorState{},
|
||||||
actors.StorageMinerActorState{},
|
actors.StorageMinerActorState{},
|
||||||
actors.StorageMinerConstructorParams{},
|
actors.StorageMinerConstructorParams{},
|
||||||
actors.CommitSectorParams{},
|
actors.OnChainSealVerifyInfo{},
|
||||||
actors.MinerInfo{},
|
actors.MinerInfo{},
|
||||||
actors.SubmitPoStParams{},
|
actors.SubmitPoStParams{},
|
||||||
actors.PieceInclVoucherData{},
|
|
||||||
actors.InclusionProof{},
|
|
||||||
actors.PaymentVerifyParams{},
|
actors.PaymentVerifyParams{},
|
||||||
actors.UpdatePeerIDParams{},
|
actors.UpdatePeerIDParams{},
|
||||||
actors.MultiSigActorState{},
|
actors.MultiSigActorState{},
|
||||||
@ -75,6 +77,31 @@ func main() {
|
|||||||
actors.ArbitrateConsensusFaultParams{},
|
actors.ArbitrateConsensusFaultParams{},
|
||||||
actors.PledgeCollateralParams{},
|
actors.PledgeCollateralParams{},
|
||||||
actors.MinerSlashConsensusFault{},
|
actors.MinerSlashConsensusFault{},
|
||||||
|
actors.StorageParticipantBalance{},
|
||||||
|
actors.StorageMarketState{},
|
||||||
|
actors.WithdrawBalanceParams{},
|
||||||
|
actors.StorageDealProposal{},
|
||||||
|
actors.StorageDeal{},
|
||||||
|
actors.PublishStorageDealsParams{},
|
||||||
|
actors.PublishStorageDealResponse{},
|
||||||
|
actors.ActivateStorageDealsParams{},
|
||||||
|
actors.ProcessStorageDealsPaymentParams{},
|
||||||
|
actors.OnChainDeal{},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gen.WriteTupleEncodersToFile("./chain/deals/cbor_gen.go", "deals",
|
||||||
|
deals.AskRequest{},
|
||||||
|
deals.AskResponse{},
|
||||||
|
deals.Proposal{},
|
||||||
|
deals.Response{},
|
||||||
|
deals.SignedResponse{},
|
||||||
|
deals.ClientDealProposal{},
|
||||||
|
deals.ClientDeal{},
|
||||||
|
deals.MinerDeal{},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package cborrpc
|
package cborrpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
|
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
ipld "github.com/ipfs/go-ipld-format"
|
||||||
logging "github.com/ipfs/go-log"
|
logging "github.com/ipfs/go-log"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
)
|
)
|
||||||
@ -43,3 +46,23 @@ func ReadCborRPC(r io.Reader, out interface{}) error {
|
|||||||
}
|
}
|
||||||
return cbor.DecodeReader(r, out)
|
return cbor.DecodeReader(r, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Dump(obj interface{}) ([]byte, error) {
|
||||||
|
var out bytes.Buffer
|
||||||
|
if err := WriteCborRPC(&out, obj); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this is a bit ugly, and this package is not exactly the best place
|
||||||
|
func AsIpld(obj interface{}) (ipld.Node, error) {
|
||||||
|
if m, ok := obj.(cbg.CBORMarshaler); ok {
|
||||||
|
b, err := Dump(m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return cbor.Decode(b, math.MaxUint64, -1)
|
||||||
|
}
|
||||||
|
return cbor.WrapObject(obj, math.MaxUint64, -1)
|
||||||
|
}
|
||||||
|
@ -212,7 +212,7 @@ func (h handlers) handle(ctx context.Context, req request, w func(func(io.Writer
|
|||||||
if handler.errOut != -1 {
|
if handler.errOut != -1 {
|
||||||
err := callResult[handler.errOut].Interface()
|
err := callResult[handler.errOut].Interface()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("error in RPC call to '%s': %s", req.Method, err)
|
log.Warnf("error in RPC call to '%s': %+v", req.Method, err)
|
||||||
resp.Error = &respError{
|
resp.Error = &respError{
|
||||||
Code: 1,
|
Code: 1,
|
||||||
Message: err.(error).Error(),
|
Message: err.(error).Error(),
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-datastore"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/address"
|
"github.com/filecoin-project/lotus/chain/address"
|
||||||
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
||||||
"github.com/filecoin-project/lotus/storage/sector"
|
"github.com/filecoin-project/lotus/storage/sector"
|
||||||
@ -40,7 +42,7 @@ func TestSealAndVerify(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
store := sector.NewStore(sb)
|
store := sector.NewStore(sb, datastore.NewMapDatastore())
|
||||||
store.Service()
|
store.Service()
|
||||||
ssinfo := <-store.Incoming()
|
ssinfo := <-store.Incoming()
|
||||||
|
|
||||||
|
14
lotuspond/front/package-lock.json
generated
14
lotuspond/front/package-lock.json
generated
@ -3457,6 +3457,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"classnames": {
|
||||||
|
"version": "2.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
|
||||||
|
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
|
||||||
|
},
|
||||||
"clean-css": {
|
"clean-css": {
|
||||||
"version": "4.2.1",
|
"version": "4.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
|
||||||
@ -10663,6 +10668,15 @@
|
|||||||
"workbox-webpack-plugin": "4.2.0"
|
"workbox-webpack-plugin": "4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-tooltip": {
|
||||||
|
"version": "3.11.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-3.11.1.tgz",
|
||||||
|
"integrity": "sha512-YCMVlEC2KuHIzOQhPplTK5jmBBwoL+PYJJdJKXj7M/h7oevupd/QSVq6z5U7/ehIGXyHsAqvwpdxexDfyQ0o3A==",
|
||||||
|
"requires": {
|
||||||
|
"classnames": "^2.2.5",
|
||||||
|
"prop-types": "^15.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"read-pkg": {
|
"read-pkg": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
"react-router-dom": "^5.0.1",
|
"react-router-dom": "^5.0.1",
|
||||||
"react-scripts": "3.0.1",
|
"react-scripts": "3.0.1",
|
||||||
|
"react-tooltip": "^3.11.1",
|
||||||
"rpc-websockets": "^4.5.1",
|
"rpc-websockets": "^4.5.1",
|
||||||
"styled-components": "^3.3.3",
|
"styled-components": "^3.3.3",
|
||||||
"xterm": "^3.14.5",
|
"xterm": "^3.14.5",
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import CID from 'cids'
|
import CID from 'cids'
|
||||||
import * as multihash from "multihashes";
|
import ReactTooltip from 'react-tooltip'
|
||||||
import State from "./State";
|
import * as multihash from "multihashes"
|
||||||
import methods from "./chain/methods";
|
import State from "./State"
|
||||||
|
import methods from "./chain/methods"
|
||||||
|
import Fil from "./Fil";
|
||||||
|
|
||||||
function truncAddr(addr, len) {
|
function truncAddr(addr, len) {
|
||||||
|
if (!addr) {
|
||||||
|
return "<!nil>"
|
||||||
|
}
|
||||||
if (addr.length > len) {
|
if (addr.length > len) {
|
||||||
return <abbr title={addr}>{addr.substr(0, len - 3) + '..'}</abbr>
|
return <abbr title={addr}>{addr.substr(0, len - 3) + '..'}</abbr>
|
||||||
}
|
}
|
||||||
@ -62,7 +67,7 @@ class Address extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openState() {
|
openState() {
|
||||||
this.props.mountWindow((onClose) => <State addr={this.props.addr} actor={this.state.actor} client={this.props.client} onClose={onClose}/>)
|
this.props.mountWindow((onClose) => <State addr={this.props.addr} actor={this.state.actor} client={this.props.client} onClose={onClose} mountWindow={this.props.mountWindow}/>)
|
||||||
}
|
}
|
||||||
|
|
||||||
async actorInfo(actor) {
|
async actorInfo(actor) {
|
||||||
@ -117,12 +122,12 @@ class Address extends React.Component {
|
|||||||
nonce = <span> <abbr title={"Next nonce"}>Nc:{this.state.nonce}</abbr>{nonce}</span>
|
nonce = <span> <abbr title={"Next nonce"}>Nc:{this.state.nonce}</abbr>{nonce}</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
let balance = <span>: {this.state.balance} </span>
|
let balance = <span>: {<Fil>{this.state.balance}</Fil>} </span>
|
||||||
if(this.props.nobalance) {
|
if(this.props.nobalance) {
|
||||||
balance = <span/>
|
balance = <span/>
|
||||||
}
|
}
|
||||||
if(this.props.short) {
|
if(this.props.short) {
|
||||||
actInfo = <span/>
|
actInfo = <ReactTooltip id={this.props.addr} place="top" type="dark" effect="solid">{actInfo}: {<Fil>this.state.balance</Fil>}</ReactTooltip>
|
||||||
balance = <span/>
|
balance = <span/>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +141,7 @@ class Address extends React.Component {
|
|||||||
minerInfo = <span> Power: {this.state.minerInfo.MinerPower} ({this.state.minerInfo.MinerPower/this.state.minerInfo.TotalPower*100}%)</span>
|
minerInfo = <span> Power: {this.state.minerInfo.MinerPower} ({this.state.minerInfo.MinerPower/this.state.minerInfo.TotalPower*100}%)</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
return <span>{addr}{balance}{actInfo}{nonce}{add20k}{transfer}{minerInfo}</span>
|
return <span data-tip data-for={this.props.addr}>{addr}{balance}{actInfo}{nonce}{add20k}{transfer}{minerInfo}</span>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,14 @@ class Block extends React.Component {
|
|||||||
<div>Miner: {<Address client={this.props.conn} addr={head.Miner} mountWindow={this.props.mountWindow}/>}</div>
|
<div>Miner: {<Address client={this.props.conn} addr={head.Miner} mountWindow={this.props.mountWindow}/>}</div>
|
||||||
<div>Messages: {head.Messages['/']} {/*TODO: link to message explorer */}</div>
|
<div>Messages: {head.Messages['/']} {/*TODO: link to message explorer */}</div>
|
||||||
<div>Parent Receipts: {head.ParentMessageReceipts['/']}</div>
|
<div>Parent Receipts: {head.ParentMessageReceipts['/']}</div>
|
||||||
<div>Parent State Root: {head.ParentStateRoot['/']}</div>
|
<div>
|
||||||
|
<span>Parent State Root: {head.ParentStateRoot['/']}</span>
|
||||||
|
<span> <Address client={this.props.conn} short={true} addr="t00" mountWindow={this.props.mountWindow}/></span>
|
||||||
|
<span> <Address client={this.props.conn} short={true} addr="t01" mountWindow={this.props.mountWindow}/></span>
|
||||||
|
<span> <Address client={this.props.conn} short={true} addr="t02" mountWindow={this.props.mountWindow}/></span>
|
||||||
|
<span> <Address client={this.props.conn} short={true} addr="t03" mountWindow={this.props.mountWindow}/></span>
|
||||||
|
<span> <Address client={this.props.conn} short={true} addr="t099" mountWindow={this.props.mountWindow}/></span>
|
||||||
|
</div>
|
||||||
<div>----</div>
|
<div>----</div>
|
||||||
<div>{messages}</div>
|
<div>{messages}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -71,10 +71,10 @@ class ChainExplorer extends React.Component {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(!base.Blocks) {
|
if(!base.Blocks) {
|
||||||
console.log("base for H is nll blk", h, base)
|
console.log("base for H is nil blk", h, base)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let cids = base.Blocks.map(b => b.Parents)
|
let cids = base.Blocks.map(b => (b.Parents || []))
|
||||||
.reduce((acc, val) => {
|
.reduce((acc, val) => {
|
||||||
let out = {...acc}
|
let out = {...acc}
|
||||||
val.forEach(c => out[c['/']] = 8)
|
val.forEach(c => out[c['/']] = 8)
|
||||||
@ -85,6 +85,10 @@ class ChainExplorer extends React.Component {
|
|||||||
|
|
||||||
const blocks = await Promise.all(cids.map(cid => this.props.client.call('Filecoin.ChainGetBlock', [cid])))
|
const blocks = await Promise.all(cids.map(cid => this.props.client.call('Filecoin.ChainGetBlock', [cid])))
|
||||||
|
|
||||||
|
if (!blocks[0]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
cache[h] = {
|
cache[h] = {
|
||||||
Height: blocks[0].Height,
|
Height: blocks[0].Height,
|
||||||
Cids: cids,
|
Cids: cids,
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Address from "./Address";
|
import Address from "./Address";
|
||||||
import Window from "./Window";
|
import Window from "./Window";
|
||||||
|
import Fil from "./Fil";
|
||||||
|
|
||||||
const dealStates = [
|
const dealStates = [
|
||||||
"Unknown",
|
"Unknown",
|
||||||
"Rejected",
|
"Rejected",
|
||||||
"Accepted",
|
"Accepted",
|
||||||
"Started",
|
|
||||||
"Failed",
|
|
||||||
"Staged",
|
"Staged",
|
||||||
"Sealing",
|
"Sealing",
|
||||||
|
"Failed",
|
||||||
"Complete",
|
"Complete",
|
||||||
"Error",
|
"Error",
|
||||||
"Expired"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -21,31 +20,43 @@ class Client extends React.Component {
|
|||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
miners: ["t0101"],
|
||||||
|
ask: {Price: "3"},
|
||||||
|
|
||||||
kbs: 1,
|
kbs: 1,
|
||||||
blocks: 12,
|
blocks: 12,
|
||||||
total: 36000,
|
total: 36000,
|
||||||
miner: "t0101",
|
miner: "t0101",
|
||||||
|
|
||||||
deals: []
|
deals: [],
|
||||||
|
|
||||||
|
blockDelay: 10,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
async componentDidMount() {
|
||||||
|
let ver = await this.props.client.call('Filecoin.Version', [])
|
||||||
|
this.setState({blockDelay: ver.BlockDelay})
|
||||||
|
|
||||||
this.getDeals()
|
this.getDeals()
|
||||||
setInterval(this.getDeals, 1325)
|
setInterval(this.getDeals, 1325)
|
||||||
}
|
}
|
||||||
|
|
||||||
getDeals = async () => {
|
getDeals = async () => {
|
||||||
|
let miners = await this.props.client.call('Filecoin.StateListMiners', [null])
|
||||||
let deals = await this.props.client.call('Filecoin.ClientListDeals', [])
|
let deals = await this.props.client.call('Filecoin.ClientListDeals', [])
|
||||||
this.setState({deals})
|
miners.sort()
|
||||||
|
this.setState({deals, miners})
|
||||||
}
|
}
|
||||||
|
|
||||||
update = (name) => (e) => this.setState({ [name]: e.target.value });
|
update = (name) => (e) => this.setState({ [name]: e.target.value });
|
||||||
|
|
||||||
makeDeal = async () => {
|
makeDeal = async () => {
|
||||||
|
let perBlk = this.state.ask.Price * this.state.kbs * 1000
|
||||||
|
|
||||||
let file = await this.props.pondClient.call('Pond.CreateRandomFile', [this.state.kbs * 1000]) // 1024 won't fit in 1k blocks :(
|
let file = await this.props.pondClient.call('Pond.CreateRandomFile', [this.state.kbs * 1000]) // 1024 won't fit in 1k blocks :(
|
||||||
let cid = await this.props.client.call('Filecoin.ClientImport', [file])
|
let cid = await this.props.client.call('Filecoin.ClientImport', [file])
|
||||||
let dealcid = await this.props.client.call('Filecoin.ClientStartDeal', [cid, this.state.miner, `${Math.round(this.state.total / this.state.blocks)}`, Number(this.state.blocks)])
|
let dealcid = await this.props.client.call('Filecoin.ClientStartDeal', [cid, this.state.miner, `${Math.round(perBlk)}`, Number(this.state.blocks)])
|
||||||
console.log("deal cid: ", dealcid)
|
console.log("deal cid: ", dealcid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,23 +78,29 @@ class Client extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let ppb = Math.round(this.state.total / this.state.blocks * 100) / 100
|
let perBlk = this.state.ask.Price * this.state.kbs * 1000
|
||||||
let ppmbb = Math.round(ppb / (this.state.kbs / 1000) * 100) / 100
|
let total = perBlk * this.state.blocks
|
||||||
|
let days = (this.state.blocks * this.state.blockDelay) / 60 / 60 / 24
|
||||||
|
|
||||||
let dealMaker = <div hidden={!this.props.pondClient}>
|
let dealMaker = <div hidden={!this.props.pondClient}>
|
||||||
<span>Make Deal: </span>
|
<div>
|
||||||
<select><option>t0101</option></select>
|
<span>Make Deal: </span>
|
||||||
<abbr title="Data length">L:</abbr> <input placeholder="KBs" defaultValue={1} onChange={this.update("kbs")}/>
|
<select>{this.state.miners.map(m => <option key={m} value={m}>{m}</option>)}</select>
|
||||||
<abbr title="Deal duration">Dur:</abbr><input placeholder="blocks" defaultValue={12} onChange={this.update("blocks")}/>
|
<span> Ask: <b><Fil>{this.state.ask.Price}</Fil></b> Fil/Byte/Block</span>
|
||||||
Total: <input placeholder="total price" defaultValue={36000} onChange={this.update("total")}/>
|
</div>
|
||||||
<span><abbr title="Price per block">PpB:</abbr> {ppb} </span>
|
<div>
|
||||||
<span><abbr title="Price per block-MiB">PpMbB:</abbr> {ppmbb} </span>
|
Data Size: <input type="text" placeholder="KBs" defaultValue={1} onChange={this.update("kbs")} style={{width: "5em"}}/>KB;
|
||||||
|
Duration:<input type="text" placeholder="blocks" defaultValue={12} onChange={this.update("blocks")} style={{width: "5em"}}/>Blocks
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Total: <Fil>{total}</Fil>; {days} Days
|
||||||
|
</div>
|
||||||
<button onClick={this.makeDeal}>Deal!</button>
|
<button onClick={this.makeDeal}>Deal!</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
let deals = this.state.deals.map((deal, i) => <div key={i}>
|
let deals = this.state.deals.map((deal, i) => <div key={i}>
|
||||||
<ul>
|
<ul>
|
||||||
<li>{i}. Proposal: {deal.ProposalCid['/'].substr(0, 18)}... <Address nobalance={true} client={this.props.client} addr={deal.Miner} mountWindow={this.props.mountWindow}/>: <b>{dealStates[deal.State]}</b>
|
<li>{i}. Proposal: {deal.ProposalCid['/'].substr(0, 18)}... <Address nobalance={true} client={this.props.client} addr={deal.Provider} mountWindow={this.props.mountWindow}/>: <b>{dealStates[deal.State]}</b>
|
||||||
{dealStates[deal.State] === 'Complete' ? <span> <a href="#" onClick={this.retrieve(deal)}>[Retrieve]</a></span> : <span/> }
|
{dealStates[deal.State] === 'Complete' ? <span> <a href="#" onClick={this.retrieve(deal)}>[Retrieve]</a></span> : <span/> }
|
||||||
<ul>
|
<ul>
|
||||||
<li>Data: {deal.PieceRef['/']}, <b>{deal.Size}</b>B; Duration: <b>{deal.Duration}</b>Blocks</li>
|
<li>Data: {deal.PieceRef['/']}, <b>{deal.Size}</b>B; Duration: <b>{deal.Duration}</b>Blocks</li>
|
||||||
@ -94,7 +111,7 @@ class Client extends React.Component {
|
|||||||
|
|
||||||
</div>)
|
</div>)
|
||||||
|
|
||||||
return <Window title={"Client - Node " + this.props.node.ID} onClose={this.props.onClose}>
|
return <Window title={"Client - Node " + this.props.node.ID} onClose={this.props.onClose} initialSize={{width: 600, height: 400}}>
|
||||||
<div className="Client">
|
<div className="Client">
|
||||||
<div>{dealMaker}</div>
|
<div>{dealMaker}</div>
|
||||||
<div>{deals}</div>
|
<div>{deals}</div>
|
||||||
|
22
lotuspond/front/src/Fil.js
Normal file
22
lotuspond/front/src/Fil.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
function filStr(raw) {
|
||||||
|
if(typeof raw !== 'string') {
|
||||||
|
raw = String(raw)
|
||||||
|
}
|
||||||
|
if(raw.length < 19) {
|
||||||
|
raw = '0'.repeat(19 - raw.length).concat(raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
let out = raw.substring(0, raw.length - 18).concat('.', raw.substring(raw.length - 18, raw.length)).replace(/\.0+$|0+$/g, '');
|
||||||
|
return out ? out : '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Fil extends React.Component {
|
||||||
|
render() {
|
||||||
|
return filStr(this.props.children)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Fil
|
@ -1,7 +1,17 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Window from "./Window";
|
import Window from "./Window";
|
||||||
|
import CID from "cids";
|
||||||
|
import * as multihash from "multihashes";
|
||||||
|
import code from "./chain/code";
|
||||||
|
import Address from "./Address";
|
||||||
|
|
||||||
class State extends React.Component {
|
class State extends React.Component {
|
||||||
|
byCode = {
|
||||||
|
[code.init]: InitState,
|
||||||
|
[code.power]: PowerState,
|
||||||
|
[code.market]: MarketState,
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
@ -9,22 +19,118 @@ class State extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props
|
const tipset = this.props.tipset || await this.props.client.call("Filecoin.ChainHead", [])
|
||||||
const actstate = await this.props.client.call('Filecoin.StateReadState', [this.props.actor, tipset])
|
const actstate = await this.props.client.call('Filecoin.StateReadState', [this.props.actor, tipset])
|
||||||
this.setState(actstate)
|
|
||||||
|
const c = new CID(this.props.actor.Code['/'])
|
||||||
|
const mh = multihash.decode(c.multihash)
|
||||||
|
let code = mh.digest.toString()
|
||||||
|
|
||||||
|
this.setState({...actstate, code: code})
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
let state
|
||||||
|
if(this.byCode[this.state.code]) {
|
||||||
|
const Stelem = this.byCode[this.state.code]
|
||||||
|
state = <Stelem client={this.props.client} mountWindow={this.props.mountWindow} tipset={this.props.tipset}/>
|
||||||
|
} else {
|
||||||
|
state = <div>{Object.keys(this.state.State).map(k => <div key={k}>{k}: <span>{JSON.stringify(this.state.State[k])}</span></div>)}</div>
|
||||||
|
}
|
||||||
|
|
||||||
const content = <div className="State">
|
const content = <div className="State">
|
||||||
<div>Balance: {this.state.Balance}</div>
|
<div>Balance: {this.state.Balance}</div>
|
||||||
<div>---</div>
|
<div>---</div>
|
||||||
<div>{Object.keys(this.state.State).map(k => <div key={k}>{k}: <span>{JSON.stringify(this.state.State[k])}</span></div>)}</div>
|
{state}
|
||||||
</div>
|
</div>
|
||||||
|
return <Window initialSize={{width: 700, height: 400}} onClose={this.props.onClose} title={`Actor ${this.props.addr} ${this.props.tipset && this.props.tipset.Height || ''} ${this.state.code}`}>
|
||||||
return <Window onClose={this.props.onClose} title={`Actor ${this.props.addr} @{this.props.ts.Height}`}>
|
|
||||||
{content}
|
{content}
|
||||||
</Window>
|
</Window>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class InitState extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {actors: []}
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props
|
||||||
|
const actors = await this.props.client.call("Filecoin.StateListActors", [tipset])
|
||||||
|
this.setState({actors: actors})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return this.state.actors.sort((a, b) => (Number(a.substr(1)) > Number(b.substr(1))))
|
||||||
|
.map(addr => <div key={addr}><Address addr={addr} client={this.props.client} mountWindow={this.props.mountWindow}/></div>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PowerState extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {actors: []}
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props
|
||||||
|
const actors = await this.props.client.call("Filecoin.StateListMiners", [tipset])
|
||||||
|
this.setState({actors: actors})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return this.state.actors.sort((a, b) => (Number(a.substr(1)) > Number(b.substr(1))))
|
||||||
|
.map(addr => <div key={addr}><Address miner={true} addr={addr} client={this.props.client} mountWindow={this.props.mountWindow}/></div>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MarketState extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {participants: {}, deals: []}
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props
|
||||||
|
const participants = await this.props.client.call("Filecoin.StateMarketParticipants", [tipset])
|
||||||
|
const deals = await this.props.client.call("Filecoin.StateMarketDeals", [tipset])
|
||||||
|
this.setState({participants, deals})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <div>
|
||||||
|
<div>
|
||||||
|
<div>Participants:</div>
|
||||||
|
<table>
|
||||||
|
<tr><td>Address</td><td>Available</td><td>Locked</td></tr>
|
||||||
|
{Object.keys(this.state.participants).map(p => <tr>
|
||||||
|
<td><Address addr={p} client={this.props.client} mountWindow={this.props.mountWindow}/></td>
|
||||||
|
<td>{this.state.participants[p].Available}</td>
|
||||||
|
<td>{this.state.participants[p].Locked}</td>
|
||||||
|
</tr>)}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>---</div>
|
||||||
|
<div>Deals:</div>
|
||||||
|
<table>
|
||||||
|
<tr><td>id</td><td>Active</td><td>Client</td><td>Provider</td><td>Size</td><td>Price</td><td>Duration</td></tr>
|
||||||
|
{Object.keys(this.state.deals).map(d => <tr>
|
||||||
|
<td>{d}</td>
|
||||||
|
<td>{this.state.deals[d].ActivationEpoch || "No"}</td>
|
||||||
|
<td><Address short={true} addr={this.state.deals[d].Deal.Proposal.Provider} client={this.props.client} mountWindow={this.props.mountWindow}/></td>
|
||||||
|
<td><Address short={true} addr={this.state.deals[d].Deal.Proposal.Client} client={this.props.client} mountWindow={this.props.mountWindow}/></td>
|
||||||
|
<td>{this.state.deals[d].Deal.Proposal.PieceSize}B</td>
|
||||||
|
<td>{this.state.deals[d].Deal.Proposal.StoragePrice}</td>
|
||||||
|
<td>{this.state.deals[d].Deal.Proposal.Duration}</td>
|
||||||
|
</tr>)}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default State
|
export default State
|
9
lotuspond/front/src/chain/code.js
Normal file
9
lotuspond/front/src/chain/code.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export default {
|
||||||
|
account: "fil/1/account",
|
||||||
|
power: "fil/1/power",
|
||||||
|
market: "fil/1/market",
|
||||||
|
miner: "fil/1/miner",
|
||||||
|
multisig: "fil/1/multisig",
|
||||||
|
init: "fil/1/init",
|
||||||
|
paych: "fil/1/paych",
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
|
import code from "./code";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
"account": [
|
[code.account]: [
|
||||||
"Send",
|
"Send",
|
||||||
"Constructor",
|
"Constructor",
|
||||||
"GetAddress",
|
"GetAddress",
|
||||||
],
|
],
|
||||||
"smarket": [
|
[code.power]: [
|
||||||
"Send",
|
"Send",
|
||||||
"Constructor",
|
"Constructor",
|
||||||
"CreateStorageMiner",
|
"CreateStorageMiner",
|
||||||
@ -15,7 +17,21 @@ export default {
|
|||||||
"IsMiner",
|
"IsMiner",
|
||||||
"StorageCollateralForSize"
|
"StorageCollateralForSize"
|
||||||
],
|
],
|
||||||
"sminer": [
|
[code.market]: [
|
||||||
|
"Send",
|
||||||
|
"Constructor",
|
||||||
|
"WithdrawBalance",
|
||||||
|
"AddBalance",
|
||||||
|
"CheckLockedBalance",
|
||||||
|
"PublishStorageDeals",
|
||||||
|
"HandleCronAction",
|
||||||
|
"SettleExpiredDeals",
|
||||||
|
"ProcessStorageDealsPayment",
|
||||||
|
"SlashStorageDealCollateral",
|
||||||
|
"GetLastExpirationFromDealIDs",
|
||||||
|
"ActivateStorageDeals",
|
||||||
|
],
|
||||||
|
[code.miner]: [
|
||||||
"Send",
|
"Send",
|
||||||
"Constructor",
|
"Constructor",
|
||||||
"CommitSector",
|
"CommitSector",
|
||||||
@ -36,7 +52,7 @@ export default {
|
|||||||
"PaymentVerifyInclusion",
|
"PaymentVerifyInclusion",
|
||||||
"PaymentVerifySector",
|
"PaymentVerifySector",
|
||||||
],
|
],
|
||||||
"multisig": [
|
[code.multisig]: [
|
||||||
"Send",
|
"Send",
|
||||||
"Constructor",
|
"Constructor",
|
||||||
"Propose",
|
"Propose",
|
||||||
@ -48,13 +64,13 @@ export default {
|
|||||||
"SwapSigner",
|
"SwapSigner",
|
||||||
"ChangeRequirement",
|
"ChangeRequirement",
|
||||||
],
|
],
|
||||||
"init": [
|
[code.init]: [
|
||||||
"Send",
|
"Send",
|
||||||
"Constructor",
|
"Constructor",
|
||||||
"Exec",
|
"Exec",
|
||||||
"GetIdForAddress"
|
"GetIdForAddress"
|
||||||
],
|
],
|
||||||
"paych": [
|
[code.paych]: [
|
||||||
"Send",
|
"Send",
|
||||||
"Constructor",
|
"Constructor",
|
||||||
"UpdateChannelState",
|
"UpdateChannelState",
|
||||||
|
@ -11,3 +11,8 @@ code {
|
|||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type=text] {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
@ -240,7 +240,7 @@ func Online() Option {
|
|||||||
Override(new(dtypes.StagingDAG), modules.StagingDAG),
|
Override(new(dtypes.StagingDAG), modules.StagingDAG),
|
||||||
|
|
||||||
Override(new(*retrieval.Miner), retrieval.NewMiner),
|
Override(new(*retrieval.Miner), retrieval.NewMiner),
|
||||||
Override(new(*deals.Handler), deals.NewHandler),
|
Override(new(*deals.Provider), deals.NewProvider),
|
||||||
Override(HandleRetrievalKey, modules.HandleRetrieval),
|
Override(HandleRetrievalKey, modules.HandleRetrieval),
|
||||||
Override(HandleDealsKey, modules.HandleDeals),
|
Override(HandleDealsKey, modules.HandleDeals),
|
||||||
Override(RunSectorServiceKey, modules.RunSectorService),
|
Override(RunSectorServiceKey, modules.RunSectorService),
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/ipfs/go-blockservice"
|
"github.com/ipfs/go-blockservice"
|
||||||
@ -13,7 +14,6 @@ import (
|
|||||||
chunker "github.com/ipfs/go-ipfs-chunker"
|
chunker "github.com/ipfs/go-ipfs-chunker"
|
||||||
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
||||||
files "github.com/ipfs/go-ipfs-files"
|
files "github.com/ipfs/go-ipfs-files"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
ipld "github.com/ipfs/go-ipld-format"
|
ipld "github.com/ipfs/go-ipld-format"
|
||||||
"github.com/ipfs/go-merkledag"
|
"github.com/ipfs/go-merkledag"
|
||||||
"github.com/ipfs/go-unixfs/importer/balanced"
|
"github.com/ipfs/go-unixfs/importer/balanced"
|
||||||
@ -76,50 +76,20 @@ func (a *API) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.A
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
vd, err := a.DealClient.VerifyParams(ctx, data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
voucherData, err := cbor.DumpObject(vd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup payments
|
// setup payments
|
||||||
total := types.BigMul(price, types.NewInt(blocksDuration))
|
total := types.BigMul(price, types.NewInt(blocksDuration))
|
||||||
|
|
||||||
// TODO: at least ping the miner before creating paych / locking the money
|
|
||||||
extra := &types.ModVerifyParams{
|
|
||||||
Actor: miner,
|
|
||||||
Method: actors.MAMethods.PaymentVerifyInclusion,
|
|
||||||
Data: voucherData,
|
|
||||||
}
|
|
||||||
|
|
||||||
head := a.Chain.GetHeaviestTipSet()
|
|
||||||
vouchers := deals.VoucherSpec(blocksDuration, total, head.Height(), extra)
|
|
||||||
|
|
||||||
payment, err := a.PaychNewPayment(ctx, self, miner, vouchers)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
proposal := deals.ClientDealProposal{
|
proposal := deals.ClientDealProposal{
|
||||||
Data: data,
|
Data: data,
|
||||||
TotalPrice: total,
|
TotalPrice: total,
|
||||||
Duration: blocksDuration,
|
ProposalExpiration: math.MaxUint64, // TODO: set something reasonable
|
||||||
Payment: actors.PaymentInfo{
|
Duration: blocksDuration,
|
||||||
PayChActor: payment.Channel,
|
ProviderAddress: miner,
|
||||||
Payer: self,
|
Client: self,
|
||||||
ChannelMessage: payment.ChannelMessage,
|
MinerID: pid,
|
||||||
Vouchers: payment.Vouchers,
|
|
||||||
},
|
|
||||||
MinerAddress: miner,
|
|
||||||
ClientAddress: self,
|
|
||||||
MinerID: pid,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := a.DealClient.Start(ctx, proposal, vd)
|
c, err := a.DealClient.Start(ctx, proposal)
|
||||||
// TODO: send updated voucher with PaymentVerifySector for cheaper validation (validate the sector the miner sent us first!)
|
// TODO: send updated voucher with PaymentVerifySector for cheaper validation (validate the sector the miner sent us first!)
|
||||||
return &c, err
|
return &c, err
|
||||||
}
|
}
|
||||||
@ -135,13 +105,12 @@ func (a *API) ClientListDeals(ctx context.Context) ([]api.DealInfo, error) {
|
|||||||
out[k] = api.DealInfo{
|
out[k] = api.DealInfo{
|
||||||
ProposalCid: v.ProposalCid,
|
ProposalCid: v.ProposalCid,
|
||||||
State: v.State,
|
State: v.State,
|
||||||
Miner: v.Proposal.MinerAddress,
|
Provider: v.Proposal.Provider,
|
||||||
|
|
||||||
PieceRef: v.Proposal.PieceRef,
|
PieceRef: v.Proposal.PieceRef,
|
||||||
CommP: v.Proposal.CommP,
|
Size: v.Proposal.PieceSize,
|
||||||
Size: v.Proposal.Size,
|
|
||||||
|
|
||||||
TotalPrice: v.Proposal.TotalPrice,
|
TotalPrice: v.Proposal.StoragePrice,
|
||||||
Duration: v.Proposal.Duration,
|
Duration: v.Proposal.Duration,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,8 @@ func (a *CommonAPI) Version(context.Context) (api.Version, error) {
|
|||||||
return api.Version{
|
return api.Version{
|
||||||
Version: build.Version,
|
Version: build.Version,
|
||||||
APIVersion: build.APIVersion,
|
APIVersion: build.APIVersion,
|
||||||
|
|
||||||
|
BlockDelay: build.BlockDelay,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package full
|
package full
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/filecoin-project/go-amt-ipld"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
"github.com/ipfs/go-hamt-ipld"
|
"github.com/ipfs/go-hamt-ipld"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
@ -54,25 +58,7 @@ func (a *StateAPI) StateMinerPower(ctx context.Context, maddr address.Address, t
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *StateAPI) StateMinerWorker(ctx context.Context, m address.Address, ts *types.TipSet) (address.Address, error) {
|
func (a *StateAPI) StateMinerWorker(ctx context.Context, m address.Address, ts *types.TipSet) (address.Address, error) {
|
||||||
ret, err := a.StateManager.Call(ctx, &types.Message{
|
return stmgr.GetMinerWorker(ctx, a.StateManager, ts, m)
|
||||||
From: m,
|
|
||||||
To: m,
|
|
||||||
Method: actors.MAMethods.GetWorkerAddr,
|
|
||||||
}, ts)
|
|
||||||
if err != nil {
|
|
||||||
return address.Undef, xerrors.Errorf("failed to get miner worker addr: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ret.ExitCode != 0 {
|
|
||||||
return address.Undef, xerrors.Errorf("failed to get miner worker addr (exit code %d)", ret.ExitCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
w, err := address.NewFromBytes(ret.Return)
|
|
||||||
if err != nil {
|
|
||||||
return address.Undef, xerrors.Errorf("GetWorkerAddr returned malformed address: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return w, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *StateAPI) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) {
|
func (a *StateAPI) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) {
|
||||||
@ -90,8 +76,8 @@ func (a *StateAPI) StatePledgeCollateral(ctx context.Context, ts *types.TipSet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret, aerr := a.StateManager.Call(ctx, &types.Message{
|
ret, aerr := a.StateManager.Call(ctx, &types.Message{
|
||||||
From: actors.StorageMarketAddress,
|
From: actors.StoragePowerAddress,
|
||||||
To: actors.StorageMarketAddress,
|
To: actors.StoragePowerAddress,
|
||||||
Method: actors.SPAMethods.PledgeCollateralForSize,
|
Method: actors.SPAMethods.PledgeCollateralForSize,
|
||||||
|
|
||||||
Params: param,
|
Params: param,
|
||||||
@ -210,7 +196,7 @@ func (a *StateAPI) StateWaitMsg(ctx context.Context, msg cid.Cid) (*api.MsgWait,
|
|||||||
|
|
||||||
func (a *StateAPI) StateListMiners(ctx context.Context, ts *types.TipSet) ([]address.Address, error) {
|
func (a *StateAPI) StateListMiners(ctx context.Context, ts *types.TipSet) ([]address.Address, error) {
|
||||||
var state actors.StoragePowerState
|
var state actors.StoragePowerState
|
||||||
if _, err := a.StateManager.LoadActorState(ctx, actors.StorageMarketAddress, &state, ts); err != nil {
|
if _, err := a.StateManager.LoadActorState(ctx, actors.StoragePowerAddress, &state, ts); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,3 +212,66 @@ func (a *StateAPI) StateListMiners(ctx context.Context, ts *types.TipSet) ([]add
|
|||||||
func (a *StateAPI) StateListActors(ctx context.Context, ts *types.TipSet) ([]address.Address, error) {
|
func (a *StateAPI) StateListActors(ctx context.Context, ts *types.TipSet) ([]address.Address, error) {
|
||||||
return a.StateManager.ListAllActors(ctx, ts)
|
return a.StateManager.ListAllActors(ctx, ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *StateAPI) StateMarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (actors.StorageParticipantBalance, error) {
|
||||||
|
return a.StateManager.MarketBalance(ctx, addr, ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *StateAPI) StateMarketParticipants(ctx context.Context, ts *types.TipSet) (map[string]actors.StorageParticipantBalance, error) {
|
||||||
|
out := map[string]actors.StorageParticipantBalance{}
|
||||||
|
|
||||||
|
var state actors.StorageMarketState
|
||||||
|
if _, err := a.StateManager.LoadActorState(ctx, actors.StorageMarketAddress, &state, ts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cst := hamt.CSTFromBstore(a.StateManager.ChainStore().Blockstore())
|
||||||
|
nd, err := hamt.LoadNode(ctx, cst, state.Balances)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nd.ForEach(ctx, func(k string, val interface{}) error {
|
||||||
|
cv := val.(*cbg.Deferred)
|
||||||
|
a, err := address.NewFromBytes([]byte(k))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var b actors.StorageParticipantBalance
|
||||||
|
if err := b.UnmarshalCBOR(bytes.NewReader(cv.Raw)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
out[a.String()] = b
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *StateAPI) StateMarketDeals(ctx context.Context, ts *types.TipSet) (map[string]actors.OnChainDeal, error) {
|
||||||
|
out := map[string]actors.OnChainDeal{}
|
||||||
|
|
||||||
|
var state actors.StorageMarketState
|
||||||
|
if _, err := a.StateManager.LoadActorState(ctx, actors.StorageMarketAddress, &state, ts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blks := amt.WrapBlockstore(a.StateManager.ChainStore().Blockstore())
|
||||||
|
da, err := amt.LoadAMT(blks, state.Deals)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := da.ForEach(func(i uint64, v *cbg.Deferred) error {
|
||||||
|
var d actors.OnChainDeal
|
||||||
|
if err := d.UnmarshalCBOR(bytes.NewReader(v.Raw)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
out[strconv.FormatInt(int64(i), 10)] = d
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
@ -33,8 +33,9 @@ func (sm *StorageMinerAPI) ActorAddress(context.Context) (address.Address, error
|
|||||||
func (sm *StorageMinerAPI) StoreGarbageData(ctx context.Context) (uint64, error) {
|
func (sm *StorageMinerAPI) StoreGarbageData(ctx context.Context) (uint64, error) {
|
||||||
size := sectorbuilder.UserBytesForSectorSize(build.SectorSize)
|
size := sectorbuilder.UserBytesForSectorSize(build.SectorSize)
|
||||||
|
|
||||||
|
// TODO: create a deal
|
||||||
name := fmt.Sprintf("fake-file-%d", rand.Intn(100000000))
|
name := fmt.Sprintf("fake-file-%d", rand.Intn(100000000))
|
||||||
sectorId, err := sm.Sectors.AddPiece(name, size, io.LimitReader(rand.New(rand.NewSource(42)), int64(size)))
|
sectorId, err := sm.Sectors.AddPiece(name, size, io.LimitReader(rand.New(rand.NewSource(42)), int64(size)), 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -98,13 +98,13 @@ func HandleRetrieval(host host.Host, lc fx.Lifecycle, m *retrieval.Miner) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleDeals(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, h *deals.Handler) {
|
func HandleDeals(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, h *deals.Provider) {
|
||||||
ctx := helpers.LifecycleCtx(mctx, lc)
|
ctx := helpers.LifecycleCtx(mctx, lc)
|
||||||
|
|
||||||
lc.Append(fx.Hook{
|
lc.Append(fx.Hook{
|
||||||
OnStart: func(context.Context) error {
|
OnStart: func(context.Context) error {
|
||||||
h.Run(ctx)
|
h.Run(ctx)
|
||||||
host.SetStreamHandler(deals.ProtocolID, h.HandleStream)
|
host.SetStreamHandler(deals.DealProtocolID, h.HandleStream)
|
||||||
host.SetStreamHandler(deals.AskProtocolID, h.HandleAskStream)
|
host.SetStreamHandler(deals.AskProtocolID, h.HandleAskStream)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
@ -19,14 +19,14 @@ func (pm *Manager) createPaych(ctx context.Context, from, to address.Address, am
|
|||||||
|
|
||||||
enc, aerr := actors.SerializeParams(&actors.ExecParams{
|
enc, aerr := actors.SerializeParams(&actors.ExecParams{
|
||||||
Params: params,
|
Params: params,
|
||||||
Code: actors.PaymentChannelActorCodeCid,
|
Code: actors.PaymentChannelCodeCid,
|
||||||
})
|
})
|
||||||
if aerr != nil {
|
if aerr != nil {
|
||||||
return address.Undef, cid.Undef, aerr
|
return address.Undef, cid.Undef, aerr
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := &types.Message{
|
msg := &types.Message{
|
||||||
To: actors.InitActorAddress,
|
To: actors.InitAddress,
|
||||||
From: from,
|
From: from,
|
||||||
Value: amt,
|
Value: amt,
|
||||||
Method: actors.IAMethods.Exec,
|
Method: actors.IAMethods.Exec,
|
||||||
|
@ -25,7 +25,7 @@ func init() {
|
|||||||
var commitmentDsPrefix = datastore.NewKey("/commitments")
|
var commitmentDsPrefix = datastore.NewKey("/commitments")
|
||||||
|
|
||||||
type Tracker struct {
|
type Tracker struct {
|
||||||
commitDs datastore.Datastore
|
commitments datastore.Datastore
|
||||||
|
|
||||||
lk sync.Mutex
|
lk sync.Mutex
|
||||||
|
|
||||||
@ -34,35 +34,36 @@ type Tracker struct {
|
|||||||
|
|
||||||
func NewTracker(ds dtypes.MetadataDS) *Tracker {
|
func NewTracker(ds dtypes.MetadataDS) *Tracker {
|
||||||
return &Tracker{
|
return &Tracker{
|
||||||
commitDs: namespace.Wrap(ds, commitmentDsPrefix),
|
commitments: namespace.Wrap(ds, commitmentDsPrefix),
|
||||||
waits: map[datastore.Key]chan struct{}{},
|
waits: map[datastore.Key]chan struct{}{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type commitment struct {
|
type commitment struct {
|
||||||
Msg cid.Cid
|
DealIDs []uint64
|
||||||
|
Msg cid.Cid
|
||||||
}
|
}
|
||||||
|
|
||||||
func commitmentKey(miner address.Address, sectorId uint64) datastore.Key {
|
func commitmentKey(miner address.Address, sectorId uint64) datastore.Key {
|
||||||
return commitmentDsPrefix.ChildString(miner.String()).ChildString(fmt.Sprintf("%d", sectorId))
|
return commitmentDsPrefix.ChildString(miner.String()).ChildString(fmt.Sprintf("%d", sectorId))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ct *Tracker) TrackCommitSectorMsg(miner address.Address, sectorId uint64, mcid cid.Cid) error {
|
func (ct *Tracker) TrackCommitSectorMsg(miner address.Address, sectorId uint64, commitMsg cid.Cid) error {
|
||||||
key := commitmentKey(miner, sectorId)
|
key := commitmentKey(miner, sectorId)
|
||||||
|
|
||||||
ct.lk.Lock()
|
ct.lk.Lock()
|
||||||
defer ct.lk.Unlock()
|
defer ct.lk.Unlock()
|
||||||
|
|
||||||
tracking, err := ct.commitDs.Get(key)
|
tracking, err := ct.commitments.Get(key)
|
||||||
switch err {
|
switch err {
|
||||||
case datastore.ErrNotFound:
|
case datastore.ErrNotFound:
|
||||||
comm := &commitment{Msg: mcid}
|
comm := &commitment{Msg: commitMsg}
|
||||||
commB, err := cbor.DumpObject(comm)
|
commB, err := cbor.DumpObject(comm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ct.commitDs.Put(key, commB); err != nil {
|
if err := ct.commitments.Put(key, commB); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,11 +79,11 @@ func (ct *Tracker) TrackCommitSectorMsg(miner address.Address, sectorId uint64,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !comm.Msg.Equals(mcid) {
|
if !comm.Msg.Equals(commitMsg) {
|
||||||
return xerrors.Errorf("commitment tracking for miner %s, sector %d: already tracking %s, got another commitment message: %s", miner, sectorId, comm.Msg, mcid)
|
return xerrors.Errorf("commitment tracking for miner %s, sector %d: already tracking %s, got another commitment message: %s", miner, sectorId, comm.Msg, commitMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Warnf("commitment.TrackCommitSectorMsg called more than once for miner %s, sector %d, message %s", miner, sectorId, mcid)
|
log.Warnf("commitment.TrackCommitSectorMsg called more than once for miner %s, sector %d, message %s", miner, sectorId, commitMsg)
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return err
|
return err
|
||||||
@ -94,7 +95,7 @@ func (ct *Tracker) WaitCommit(ctx context.Context, miner address.Address, sector
|
|||||||
|
|
||||||
ct.lk.Lock()
|
ct.lk.Lock()
|
||||||
|
|
||||||
tracking, err := ct.commitDs.Get(key)
|
tracking, err := ct.commitments.Get(key)
|
||||||
if err != datastore.ErrNotFound {
|
if err != datastore.ErrNotFound {
|
||||||
ct.lk.Unlock()
|
ct.lk.Unlock()
|
||||||
|
|
||||||
@ -120,7 +121,7 @@ func (ct *Tracker) WaitCommit(ctx context.Context, miner address.Address, sector
|
|||||||
|
|
||||||
select {
|
select {
|
||||||
case <-wait:
|
case <-wait:
|
||||||
tracking, err := ct.commitDs.Get(key)
|
tracking, err := ct.commitments.Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("failed to get commitment after waiting: %w", err)
|
return cid.Undef, xerrors.Errorf("failed to get commitment after waiting: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
logging "github.com/ipfs/go-log"
|
logging "github.com/ipfs/go-log"
|
||||||
"github.com/libp2p/go-libp2p-core/host"
|
"github.com/libp2p/go-libp2p-core/host"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
@ -129,12 +130,19 @@ func (m *Miner) commitSector(ctx context.Context, sinfo sectorbuilder.SectorSeal
|
|||||||
log.Error("seal we just created failed verification")
|
log.Error("seal we just created failed verification")
|
||||||
}
|
}
|
||||||
|
|
||||||
params := &actors.CommitSectorParams{
|
deals, err := m.secst.DealsForCommit(sinfo.SectorID)
|
||||||
SectorID: sinfo.SectorID,
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting sector deals failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
params := &actors.OnChainSealVerifyInfo{
|
||||||
CommD: sinfo.CommD[:],
|
CommD: sinfo.CommD[:],
|
||||||
CommR: sinfo.CommR[:],
|
CommR: sinfo.CommR[:],
|
||||||
CommRStar: sinfo.CommRStar[:],
|
CommRStar: sinfo.CommRStar[:],
|
||||||
Proof: sinfo.Proof,
|
Proof: sinfo.Proof,
|
||||||
|
|
||||||
|
DealIDs: deals,
|
||||||
|
SectorNumber: sinfo.SectorID,
|
||||||
}
|
}
|
||||||
enc, aerr := actors.SerializeParams(params)
|
enc, aerr := actors.SerializeParams(params)
|
||||||
if aerr != nil {
|
if aerr != nil {
|
||||||
|
@ -2,25 +2,45 @@ package sector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/filecoin-project/go-sectorbuilder/sealing_state"
|
"fmt"
|
||||||
"golang.org/x/xerrors"
|
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-sectorbuilder/sealing_state"
|
||||||
|
"github.com/ipfs/go-datastore"
|
||||||
|
"github.com/ipfs/go-datastore/namespace"
|
||||||
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
logging "github.com/ipfs/go-log"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
||||||
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
logging "github.com/ipfs/go-log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cbor.RegisterCborType(dealMapping{})
|
||||||
|
}
|
||||||
|
|
||||||
var log = logging.Logger("sectorstore")
|
var log = logging.Logger("sectorstore")
|
||||||
|
|
||||||
|
var sectorDealsPrefix = datastore.NewKey("/sectordeals")
|
||||||
|
|
||||||
|
type dealMapping struct {
|
||||||
|
DealIDs []uint64
|
||||||
|
Committed bool
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: eventually handle sector storage here instead of in rust-sectorbuilder
|
// TODO: eventually handle sector storage here instead of in rust-sectorbuilder
|
||||||
type Store struct {
|
type Store struct {
|
||||||
lk sync.Mutex
|
waitingLk sync.Mutex
|
||||||
|
|
||||||
sb *sectorbuilder.SectorBuilder
|
sb *sectorbuilder.SectorBuilder
|
||||||
|
|
||||||
|
dealsLk sync.Mutex
|
||||||
|
deals datastore.Datastore
|
||||||
|
|
||||||
waiting map[uint64]chan struct{}
|
waiting map[uint64]chan struct{}
|
||||||
incoming []chan sectorbuilder.SectorSealingStatus
|
incoming []chan sectorbuilder.SectorSealingStatus
|
||||||
// TODO: outdated chan
|
// TODO: outdated chan
|
||||||
@ -28,9 +48,10 @@ type Store struct {
|
|||||||
closeCh chan struct{}
|
closeCh chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStore(sb *sectorbuilder.SectorBuilder) *Store {
|
func NewStore(sb *sectorbuilder.SectorBuilder, ds dtypes.MetadataDS) *Store {
|
||||||
return &Store{
|
return &Store{
|
||||||
sb: sb,
|
sb: sb,
|
||||||
|
deals: namespace.Wrap(ds, sectorDealsPrefix),
|
||||||
waiting: map[uint64]chan struct{}{},
|
waiting: map[uint64]chan struct{}{},
|
||||||
closeCh: make(chan struct{}),
|
closeCh: make(chan struct{}),
|
||||||
}
|
}
|
||||||
@ -44,13 +65,13 @@ func (s *Store) poll() {
|
|||||||
log.Debug("polling for sealed sectors...")
|
log.Debug("polling for sealed sectors...")
|
||||||
|
|
||||||
// get a list of sectors to poll
|
// get a list of sectors to poll
|
||||||
s.lk.Lock()
|
s.waitingLk.Lock()
|
||||||
toPoll := make([]uint64, 0, len(s.waiting))
|
toPoll := make([]uint64, 0, len(s.waiting))
|
||||||
|
|
||||||
for id := range s.waiting {
|
for id := range s.waiting {
|
||||||
toPoll = append(toPoll, id)
|
toPoll = append(toPoll, id)
|
||||||
}
|
}
|
||||||
s.lk.Unlock()
|
s.waitingLk.Unlock()
|
||||||
|
|
||||||
var done []sectorbuilder.SectorSealingStatus
|
var done []sectorbuilder.SectorSealingStatus
|
||||||
|
|
||||||
@ -68,7 +89,7 @@ func (s *Store) poll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send updates
|
// send updates
|
||||||
s.lk.Lock()
|
s.waitingLk.Lock()
|
||||||
for _, sector := range done {
|
for _, sector := range done {
|
||||||
watch, ok := s.waiting[sector.SectorID]
|
watch, ok := s.waiting[sector.SectorID]
|
||||||
if ok {
|
if ok {
|
||||||
@ -79,7 +100,7 @@ func (s *Store) poll() {
|
|||||||
c <- sector // TODO: ctx!
|
c <- sector // TODO: ctx!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.lk.Unlock()
|
s.waitingLk.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) service() {
|
func (s *Store) service() {
|
||||||
@ -90,35 +111,97 @@ func (s *Store) service() {
|
|||||||
case <-poll:
|
case <-poll:
|
||||||
s.poll()
|
s.poll()
|
||||||
case <-s.closeCh:
|
case <-s.closeCh:
|
||||||
s.lk.Lock()
|
s.waitingLk.Lock()
|
||||||
for _, c := range s.incoming {
|
for _, c := range s.incoming {
|
||||||
close(c)
|
close(c)
|
||||||
}
|
}
|
||||||
s.lk.Unlock()
|
s.waitingLk.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) AddPiece(ref string, size uint64, r io.Reader) (sectorID uint64, err error) {
|
func (s *Store) AddPiece(ref string, size uint64, r io.Reader, dealID uint64) (sectorID uint64, err error) {
|
||||||
sectorID, err = s.sb.AddPiece(ref, size, r)
|
sectorID, err = s.sb.AddPiece(ref, size, r)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.lk.Lock()
|
s.waitingLk.Lock()
|
||||||
_, exists := s.waiting[sectorID]
|
_, exists := s.waiting[sectorID]
|
||||||
if !exists { // pieces can share sectors
|
if !exists { // pieces can share sectors
|
||||||
s.waiting[sectorID] = make(chan struct{})
|
s.waiting[sectorID] = make(chan struct{})
|
||||||
}
|
}
|
||||||
s.lk.Unlock()
|
s.waitingLk.Unlock()
|
||||||
|
|
||||||
|
s.dealsLk.Lock()
|
||||||
|
defer s.dealsLk.Unlock()
|
||||||
|
|
||||||
|
k := datastore.NewKey(fmt.Sprint(sectorID))
|
||||||
|
e, err := s.deals.Get(k)
|
||||||
|
var deals dealMapping
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
if err := cbor.DecodeInto(e, &deals); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if deals.Committed {
|
||||||
|
return 0, xerrors.Errorf("sector %d already committed", sectorID)
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case datastore.ErrNotFound:
|
||||||
|
deals.DealIDs = append(deals.DealIDs, dealID)
|
||||||
|
d, err := cbor.DumpObject(&deals)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if err := s.deals.Put(k, d); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
return sectorID, nil
|
return sectorID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) DealsForCommit(sectorID uint64) ([]uint64, error) {
|
||||||
|
s.dealsLk.Lock()
|
||||||
|
defer s.dealsLk.Unlock()
|
||||||
|
|
||||||
|
k := datastore.NewKey(fmt.Sprint(sectorID))
|
||||||
|
e, err := s.deals.Get(k)
|
||||||
|
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
var deals dealMapping
|
||||||
|
if err := cbor.DecodeInto(e, &deals); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if deals.Committed {
|
||||||
|
log.Errorf("getting deal IDs for sector %d: sector already marked as committed", sectorID)
|
||||||
|
}
|
||||||
|
|
||||||
|
deals.Committed = true
|
||||||
|
d, err := cbor.DumpObject(&deals)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := s.deals.Put(k, d); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return deals.DealIDs, nil
|
||||||
|
case datastore.ErrNotFound:
|
||||||
|
log.Errorf("getting deal IDs for sector %d failed: %s", err)
|
||||||
|
return []uint64{}, nil
|
||||||
|
default:
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) CloseIncoming(c <-chan sectorbuilder.SectorSealingStatus) {
|
func (s *Store) CloseIncoming(c <-chan sectorbuilder.SectorSealingStatus) {
|
||||||
s.lk.Lock()
|
s.waitingLk.Lock()
|
||||||
var at = -1
|
var at = -1
|
||||||
for i, ch := range s.incoming {
|
for i, ch := range s.incoming {
|
||||||
if ch == c {
|
if ch == c {
|
||||||
@ -126,7 +209,7 @@ func (s *Store) CloseIncoming(c <-chan sectorbuilder.SectorSealingStatus) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if at == -1 {
|
if at == -1 {
|
||||||
s.lk.Unlock()
|
s.waitingLk.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(s.incoming) > 1 {
|
if len(s.incoming) > 1 {
|
||||||
@ -135,21 +218,21 @@ func (s *Store) CloseIncoming(c <-chan sectorbuilder.SectorSealingStatus) {
|
|||||||
s.incoming[last] = nil
|
s.incoming[last] = nil
|
||||||
}
|
}
|
||||||
s.incoming = s.incoming[:len(s.incoming)-1]
|
s.incoming = s.incoming[:len(s.incoming)-1]
|
||||||
s.lk.Unlock()
|
s.waitingLk.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) Incoming() <-chan sectorbuilder.SectorSealingStatus {
|
func (s *Store) Incoming() <-chan sectorbuilder.SectorSealingStatus {
|
||||||
ch := make(chan sectorbuilder.SectorSealingStatus, 8)
|
ch := make(chan sectorbuilder.SectorSealingStatus, 8)
|
||||||
s.lk.Lock()
|
s.waitingLk.Lock()
|
||||||
s.incoming = append(s.incoming, ch)
|
s.incoming = append(s.incoming, ch)
|
||||||
s.lk.Unlock()
|
s.waitingLk.Unlock()
|
||||||
return ch
|
return ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) WaitSeal(ctx context.Context, sector uint64) (sectorbuilder.SectorSealingStatus, error) {
|
func (s *Store) WaitSeal(ctx context.Context, sector uint64) (sectorbuilder.SectorSealingStatus, error) {
|
||||||
s.lk.Lock()
|
s.waitingLk.Lock()
|
||||||
watch, ok := s.waiting[sector]
|
watch, ok := s.waiting[sector]
|
||||||
s.lk.Unlock()
|
s.waitingLk.Unlock()
|
||||||
if ok {
|
if ok {
|
||||||
select {
|
select {
|
||||||
case <-watch:
|
case <-watch:
|
||||||
|
@ -153,7 +153,7 @@ func (r *refStorer) Read(p []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SectorBlocks) AddUnixfsPiece(ref cid.Cid, r UnixfsReader, keepAtLeast uint64) (sectorID uint64, err error) {
|
func (st *SectorBlocks) AddUnixfsPiece(ref cid.Cid, r UnixfsReader, dealID uint64) (sectorID uint64, err error) {
|
||||||
size, err := r.Size()
|
size, err := r.Size()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
@ -166,7 +166,7 @@ func (st *SectorBlocks) AddUnixfsPiece(ref cid.Cid, r UnixfsReader, keepAtLeast
|
|||||||
intermediate: st.intermediate,
|
intermediate: st.intermediate,
|
||||||
}
|
}
|
||||||
|
|
||||||
return st.Store.AddPiece(refst.pieceRef, uint64(size), refst)
|
return st.Store.AddPiece(refst.pieceRef, uint64(size), refst, dealID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *SectorBlocks) List() (map[cid.Cid][]api.SealedRef, error) {
|
func (st *SectorBlocks) List() (map[cid.Cid][]api.SealedRef, error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user