commit
340e9177b2
2
Makefile
2
Makefile
@ -100,7 +100,7 @@ townhall:
|
||||
rm -f townhall
|
||||
go build -o townhall ./cmd/lotus-townhall
|
||||
(cd ./cmd/lotus-townhall/townhall && npm i && npm run build)
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec townhall -i ./cmd/lotus-townhall
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec townhall -i ./cmd/lotus-townhall -i ./build
|
||||
.PHONY: townhall
|
||||
|
||||
fountain:
|
||||
|
17
README.md
17
README.md
@ -92,19 +92,20 @@ $ lotus wallet balance [optional address (t3...)]
|
||||
|
||||
### Mining
|
||||
|
||||
Ensure that at least one BLS address (`t3..`) in your wallet has enough funds to
|
||||
cover pledge collateral:
|
||||
Ensure that at least one BLS address (`t3..`) in your wallet exists
|
||||
```sh
|
||||
$ lotus state pledge-collateral
|
||||
1234
|
||||
$ lotus wallet balance [t3...]
|
||||
8999
|
||||
$ lotus wallet list
|
||||
t3...
|
||||
```
|
||||
(Balance must be higher than the returned pledge collateral for the next step to work)
|
||||
With this address, go to https://lotus-faucet.kittyhawk.wtf/miner.html, and
|
||||
click `Create Miner`
|
||||
|
||||
Wait for a page telling you the address of the newly created storage miner to
|
||||
appear - It should be saying: `New storage miners address is: t0..`
|
||||
|
||||
Initialize storage miner:
|
||||
```sh
|
||||
$ lotus-storage-miner init --owner=t3...
|
||||
$ lotus-storage-miner init --actor=t01.. --owner=t3....
|
||||
```
|
||||
This command should return successfully after miner is setup on-chain (30-60s)
|
||||
|
||||
|
24
api/api.go
24
api/api.go
@ -12,6 +12,7 @@ import (
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
"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/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@ -101,7 +102,7 @@ type FullNode interface {
|
||||
|
||||
// ClientImport imports file under the specified path into filestore
|
||||
ClientImport(ctx context.Context, path string) (cid.Cid, error)
|
||||
ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, price types.BigInt, blocksDuration uint64) (*cid.Cid, error)
|
||||
ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, epochPrice types.BigInt, blocksDuration uint64) (*cid.Cid, error)
|
||||
ClientListDeals(ctx context.Context) ([]DealInfo, error)
|
||||
ClientHasLocal(ctx context.Context, root cid.Cid) (bool, error)
|
||||
ClientFindData(ctx context.Context, root cid.Cid) ([]QueryOffer, error) // TODO: specify serialization mode we want (defaults to unixfs for now)
|
||||
@ -122,16 +123,20 @@ type FullNode interface {
|
||||
StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error)
|
||||
StateReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*ActorState, error)
|
||||
|
||||
StateMinerSectors(context.Context, address.Address) ([]*SectorInfo, error)
|
||||
StateMinerSectors(context.Context, address.Address, *types.TipSet) ([]*SectorInfo, error)
|
||||
StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*SectorInfo, error)
|
||||
StateMinerPower(context.Context, address.Address, *types.TipSet) (MinerPower, error)
|
||||
StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error)
|
||||
StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error)
|
||||
StateMinerProvingPeriodEnd(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error)
|
||||
StateMinerSectorSize(context.Context, address.Address, *types.TipSet) (uint64, error)
|
||||
StatePledgeCollateral(context.Context, *types.TipSet) (types.BigInt, error)
|
||||
StateWaitMsg(context.Context, cid.Cid) (*MsgWait, error)
|
||||
StateListMiners(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)
|
||||
PaychList(context.Context) ([]address.Address, error)
|
||||
@ -162,9 +167,6 @@ type StorageMiner interface {
|
||||
// List all staged sectors
|
||||
SectorsList(context.Context) ([]uint64, error)
|
||||
|
||||
// Seal all staged sectors
|
||||
SectorsStagedSeal(context.Context) error
|
||||
|
||||
SectorsRefs(context.Context) (map[string][]SealedRef, error)
|
||||
}
|
||||
|
||||
@ -179,6 +181,9 @@ type Version struct {
|
||||
APIVersion uint32
|
||||
|
||||
// TODO: git commit / os / genesis cid?
|
||||
|
||||
// Seconds
|
||||
BlockDelay uint64
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
@ -196,14 +201,13 @@ type Import struct {
|
||||
type DealInfo struct {
|
||||
ProposalCid cid.Cid
|
||||
State DealState
|
||||
Miner address.Address
|
||||
Provider address.Address
|
||||
|
||||
PieceRef cid.Cid
|
||||
CommP []byte
|
||||
PieceRef []byte // cid bytes
|
||||
Size uint64
|
||||
|
||||
TotalPrice types.BigInt
|
||||
Duration uint64
|
||||
PricePerEpoch types.BigInt
|
||||
Duration uint64
|
||||
}
|
||||
|
||||
type MsgWait struct {
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
"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/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@ -85,20 +86,24 @@ type FullNodeStruct struct {
|
||||
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"`
|
||||
|
||||
StateMinerSectors func(context.Context, address.Address) ([]*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"`
|
||||
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"`
|
||||
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"`
|
||||
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"`
|
||||
StateReadState func(context.Context, *types.Actor, *types.TipSet) (*ActorState, error) `perm:"read"`
|
||||
StatePledgeCollateral func(context.Context, *types.TipSet) (types.BigInt, error) `perm:"read"`
|
||||
StateWaitMsg func(context.Context, cid.Cid) (*MsgWait, 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"`
|
||||
StateMinerSectors 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"`
|
||||
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"`
|
||||
StateMinerProvingPeriodEnd func(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) `perm:"read"`
|
||||
StateMinerSectorSize func(context.Context, address.Address, *types.TipSet) (uint64, 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"`
|
||||
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"`
|
||||
StatePledgeCollateral func(context.Context, *types.TipSet) (types.BigInt, error) `perm:"read"`
|
||||
StateWaitMsg func(context.Context, cid.Cid) (*MsgWait, 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"`
|
||||
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"`
|
||||
PaychList func(context.Context) ([]address.Address, error) `perm:"read"`
|
||||
@ -124,9 +129,8 @@ type StorageMinerStruct struct {
|
||||
|
||||
StoreGarbageData func(context.Context) (uint64, error) `perm:"write"`
|
||||
|
||||
SectorsStatus func(context.Context, uint64) (sectorbuilder.SectorSealingStatus, error) `perm:"read"`
|
||||
SectorsList func(context.Context) ([]uint64, error) `perm:"read"`
|
||||
SectorsStagedSeal func(context.Context) error `perm:"write"`
|
||||
SectorsStatus func(context.Context, uint64) (sectorbuilder.SectorSealingStatus, error) `perm:"read"`
|
||||
SectorsList func(context.Context) ([]uint64, error) `perm:"read"`
|
||||
|
||||
SectorsRefs func(context.Context) (map[string][]SealedRef, error) `perm:"read"`
|
||||
}
|
||||
@ -334,8 +338,8 @@ func (c *FullNodeStruct) SyncSubmitBlock(ctx context.Context, blk *types.BlockMs
|
||||
return c.Internal.SyncSubmitBlock(ctx, blk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address) ([]*SectorInfo, error) {
|
||||
return c.Internal.StateMinerSectors(ctx, addr)
|
||||
func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*SectorInfo, error) {
|
||||
return c.Internal.StateMinerSectors(ctx, addr, ts)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*SectorInfo, error) {
|
||||
@ -353,10 +357,15 @@ func (c *FullNodeStruct) StateMinerWorker(ctx context.Context, m address.Address
|
||||
func (c *FullNodeStruct) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) {
|
||||
return c.Internal.StateMinerPeerID(ctx, m, ts)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerProvingPeriodEnd(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) {
|
||||
return c.Internal.StateMinerProvingPeriodEnd(ctx, actor, ts)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerSectorSize(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) {
|
||||
return c.Internal.StateMinerSectorSize(ctx, actor, ts)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
|
||||
return c.Internal.StateCall(ctx, msg, ts)
|
||||
}
|
||||
@ -388,6 +397,18 @@ func (c *FullNodeStruct) StateListActors(ctx context.Context, ts *types.TipSet)
|
||||
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) {
|
||||
return c.Internal.PaychGet(ctx, from, to, ensureFunds)
|
||||
}
|
||||
@ -454,11 +475,6 @@ func (c *StorageMinerStruct) SectorsList(ctx context.Context) ([]uint64, error)
|
||||
return c.Internal.SectorsList(ctx)
|
||||
}
|
||||
|
||||
// Seal all staged sectors
|
||||
func (c *StorageMinerStruct) SectorsStagedSeal(ctx context.Context) error {
|
||||
return c.Internal.SectorsStagedSeal(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorsRefs(ctx context.Context) (map[string][]SealedRef, error) {
|
||||
return c.Internal.SectorsRefs(ctx)
|
||||
}
|
||||
|
15
api/types.go
15
api/types.go
@ -6,22 +6,21 @@ import (
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
type DealState int
|
||||
type DealState = uint64
|
||||
|
||||
const (
|
||||
DealUnknown = DealState(iota)
|
||||
DealRejected
|
||||
DealAccepted
|
||||
DealStarted
|
||||
DealUnknown = DealState(iota)
|
||||
DealRejected // Provider didn't like the proposal
|
||||
DealAccepted // Proposal accepted, data moved
|
||||
DealStaged // Data put into the sector
|
||||
DealSealing // Data in process of being sealed
|
||||
|
||||
DealFailed
|
||||
DealStaged
|
||||
DealSealing
|
||||
DealComplete
|
||||
|
||||
// Internal
|
||||
|
||||
DealError // deal failed with an unexpected error
|
||||
DealExpired
|
||||
|
||||
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
|
||||
}
|
@ -1 +1 @@
|
||||
/ip4/147.75.80.17/tcp/1347/p2p/12D3KooWQ3NBPgTbXFRGnmpZUpYBSPJtwJfxuAFHBuWJ8LumCYf2
|
||||
/ip4/147.75.80.17/tcp/1347/p2p/12D3KooWPTYfTi7B1mQpbyRaCT65Trf7zW9npmihcF1xPfZogrzh
|
||||
|
@ -1 +1 @@
|
||||
/ip4/147.75.80.29/tcp/1347/p2p/12D3KooWGU8C1mFsEtz4bXmHUH3kQTnQnxVy8cigwGV94qCpYJw7
|
||||
/ip4/147.75.80.29/tcp/1347/p2p/12D3KooWEwGkxuG4BSvWUU8Sf69rxUYjWHAMT2qFVBhzGJZAXc6v
|
||||
|
Binary file not shown.
@ -8,16 +8,20 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
rice "github.com/GeertJohan/go.rice"
|
||||
logging "github.com/ipfs/go-log"
|
||||
"github.com/minio/blake2b-simd"
|
||||
"go.uber.org/multierr"
|
||||
"golang.org/x/xerrors"
|
||||
pb "gopkg.in/cheggaaa/pb.v1"
|
||||
)
|
||||
|
||||
var log = logging.Logger("build")
|
||||
|
||||
const gateway = "http://198.211.99.118/ipfs/"
|
||||
//const gateway = "http://198.211.99.118/ipfs/"
|
||||
const gateway = "https://ipfs.io/ipfs/"
|
||||
const paramdir = "/var/tmp/filecoin-proof-parameters"
|
||||
|
||||
type paramFile struct {
|
||||
@ -26,6 +30,13 @@ type paramFile struct {
|
||||
SectorSize uint64 `json:"sector_size"`
|
||||
}
|
||||
|
||||
type fetch struct {
|
||||
wg sync.WaitGroup
|
||||
fetchLk sync.Mutex
|
||||
|
||||
errs []error
|
||||
}
|
||||
|
||||
func GetParams(storage bool) error {
|
||||
if err := os.Mkdir(paramdir, 0755); err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
@ -38,43 +49,71 @@ func GetParams(storage bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ft := &fetch{}
|
||||
|
||||
for name, info := range params {
|
||||
if info.SectorSize != SectorSize {
|
||||
if !SupportedSectorSize(info.SectorSize) {
|
||||
continue
|
||||
}
|
||||
if !storage && strings.HasSuffix(name, ".params") {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := maybeFetch(name, info); err != nil {
|
||||
return err
|
||||
}
|
||||
ft.maybeFetchAsync(name, info)
|
||||
}
|
||||
|
||||
return nil
|
||||
return ft.wait()
|
||||
}
|
||||
|
||||
func maybeFetch(name string, info paramFile) error {
|
||||
path := filepath.Join(paramdir, name)
|
||||
func (ft *fetch) maybeFetchAsync(name string, info paramFile) {
|
||||
ft.wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer ft.wg.Done()
|
||||
|
||||
path := filepath.Join(paramdir, name)
|
||||
|
||||
err := ft.checkFile(path, info)
|
||||
if !os.IsNotExist(err) && err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ft.fetchLk.Lock()
|
||||
defer ft.fetchLk.Unlock()
|
||||
|
||||
if err := doFetch(path, info); err != nil {
|
||||
ft.errs = append(ft.errs, xerrors.Errorf("fetching file %s: %w", path, err))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (ft *fetch) checkFile(path string, info paramFile) error {
|
||||
f, err := os.Open(path)
|
||||
if err == nil {
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
h := blake2b.New512()
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sum := h.Sum(nil)
|
||||
strSum := hex.EncodeToString(sum[:16])
|
||||
if strSum == info.Digest {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Warnf("Checksum mismatch in param file %s, %s != %s", name, strSum, info.Digest)
|
||||
h := blake2b.New512()
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return doFetch(path, info)
|
||||
sum := h.Sum(nil)
|
||||
strSum := hex.EncodeToString(sum[:16])
|
||||
if strSum == info.Digest {
|
||||
return nil
|
||||
}
|
||||
|
||||
return xerrors.Errorf("checksum mismatch in param file %s, %s != %s", path, strSum, info.Digest)
|
||||
}
|
||||
|
||||
func (ft *fetch) wait() error {
|
||||
ft.wg.Wait()
|
||||
return multierr.Combine(ft.errs...)
|
||||
}
|
||||
|
||||
func doFetch(out string, info paramFile) error {
|
||||
|
@ -1,6 +1,8 @@
|
||||
package build
|
||||
|
||||
import "math/big"
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// Core network constants
|
||||
|
||||
@ -10,7 +12,20 @@ import "math/big"
|
||||
const UnixfsChunkSize uint64 = 1 << 20
|
||||
const UnixfsLinksPerLevel = 1024
|
||||
|
||||
const SectorSize = 16 << 20
|
||||
var SectorSizes = []uint64{
|
||||
16 << 20,
|
||||
256 << 20,
|
||||
1 << 30,
|
||||
}
|
||||
|
||||
func SupportedSectorSize(ssize uint64) bool {
|
||||
for _, ss := range SectorSizes {
|
||||
if ssize == ss {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// /////
|
||||
// Payments
|
||||
@ -18,19 +33,11 @@ const SectorSize = 16 << 20
|
||||
// Blocks
|
||||
const PaymentChannelClosingDelay = 6 * 60 * 2 // six hours
|
||||
|
||||
// Blocks
|
||||
const DealVoucherSkewLimit = 10
|
||||
|
||||
// Blocks
|
||||
const MinDealVoucherIncrement = ProvingPeriodDuration
|
||||
|
||||
const MaxVouchersPerDeal = 768 // roughly one voucher per 10h over a year
|
||||
|
||||
// /////
|
||||
// Consensus / Network
|
||||
|
||||
// Seconds
|
||||
const BlockDelay = 30
|
||||
const BlockDelay = 10
|
||||
|
||||
// Seconds
|
||||
const AllowableClockDrift = BlockDelay * 2
|
||||
@ -39,19 +46,36 @@ const AllowableClockDrift = BlockDelay * 2
|
||||
const ForkLengthThreshold = 100
|
||||
|
||||
// Blocks (e)
|
||||
const BlocksPerEpoch = 1
|
||||
const BlocksPerEpoch = 3
|
||||
|
||||
// Blocks
|
||||
const Finality = 500
|
||||
|
||||
// /////
|
||||
// Proofs / Mining
|
||||
// Proofs
|
||||
|
||||
// Blocks
|
||||
const RandomnessLookback = 20
|
||||
const ProvingPeriodDuration = 60
|
||||
|
||||
// PoStChallangeTime sets the window in which post computation should happen
|
||||
// Blocks
|
||||
const PoStChallangeTime = ProvingPeriodDuration - 6
|
||||
|
||||
// PoStRandomnessLookback is additional randomness lookback for PoSt computation
|
||||
// To compute randomness epoch in a given proving period:
|
||||
// RandH = PPE - PoStChallangeTime - PoStRandomnessLookback
|
||||
//
|
||||
// Blocks
|
||||
const PoStRandomnessLookback = 1
|
||||
|
||||
// Blocks
|
||||
const ProvingPeriodDuration = 40
|
||||
const SealRandomnessLookback = Finality
|
||||
|
||||
// /////
|
||||
// Mining
|
||||
|
||||
// Blocks
|
||||
const PoSTChallangeTime = 20
|
||||
const EcRandomnessLookback = 300
|
||||
|
||||
const PowerCollateralProportion = 5
|
||||
const PerCapitaCollateralProportion = 1
|
||||
|
@ -1,82 +1,82 @@
|
||||
{
|
||||
"v12-proof-of-spacetime-rational-535d1050e3adca2a0dfe6c3c0c4fa12097c9a7835fb969042f82a507b13310e0.params": {
|
||||
"cid": "QmZ6Y88jRbRjjYQzhh8o85bcUeChj7NGyo9yK6VbywhJ9F",
|
||||
"digest": "3d245479d9b5fc668d58c493da5f3ee1",
|
||||
"v14-proof-of-spacetime-rational-535d1050e3adca2a0dfe6c3c0c4fa12097c9a7835fb969042f82a507b13310e0.params": {
|
||||
"cid": "QmT22f1Np1GpW29NXD7Zrv3Ae4poMYhmkDjyscqL8QrJXY",
|
||||
"digest": "989fd8d989e0f7f1fe21bb010cf1b231",
|
||||
"sector_size": 16777216
|
||||
},
|
||||
"v12-proof-of-spacetime-rational-535d1050e3adca2a0dfe6c3c0c4fa12097c9a7835fb969042f82a507b13310e0.vk": {
|
||||
"cid": "QmbGgBLMTCnRc1E1fsUCPyZE4SYzrtAYEWCqCtL55AgxE2",
|
||||
"digest": "29bd4c152096f878f41257b433159d81",
|
||||
"v14-proof-of-spacetime-rational-535d1050e3adca2a0dfe6c3c0c4fa12097c9a7835fb969042f82a507b13310e0.vk": {
|
||||
"cid": "QmVqSdc23to4UwduCCb25223rpSccvtcgPMfRKY1qjucDc",
|
||||
"digest": "c6d258c37243b8544238a98100e3e399",
|
||||
"sector_size": 16777216
|
||||
},
|
||||
"v12-proof-of-spacetime-rational-b99f15d0bdaaf4ffb68b2ca72b69ea8d915f66a2a56f667430ad69d87aa5febd.params": {
|
||||
"cid": "Qmdm8vhWeRsZUUaHdysDr91gv6u6RFeC18hHxGnnzPrwcW",
|
||||
"digest": "c67fd415a65e6d1caf4278597cf3462e",
|
||||
"v14-proof-of-spacetime-rational-b99f15d0bdaaf4ffb68b2ca72b69ea8d915f66a2a56f667430ad69d87aa5febd.params": {
|
||||
"cid": "QmRTCqgokEGTMfWVaSr7qFXTNotmpd2QBEi8RsvSQKmPLz",
|
||||
"digest": "ff77a5e270afc6e1c7fbc19e48348fac",
|
||||
"sector_size": 1073741824
|
||||
},
|
||||
"v12-proof-of-spacetime-rational-b99f15d0bdaaf4ffb68b2ca72b69ea8d915f66a2a56f667430ad69d87aa5febd.vk": {
|
||||
"cid": "Qmc3xssw1syaZDZKmiM7TbCRnoDPfmD6V8ec1eTESidJQS",
|
||||
"digest": "870355c10000010b9a4ece80892acca2",
|
||||
"v14-proof-of-spacetime-rational-b99f15d0bdaaf4ffb68b2ca72b69ea8d915f66a2a56f667430ad69d87aa5febd.vk": {
|
||||
"cid": "QmRssVAXRN3xp9VdSpTq1pNjkob3QiikoFZiM5hqrmh1VU",
|
||||
"digest": "b41f35ac26224258e366327716a835a4",
|
||||
"sector_size": 1073741824
|
||||
},
|
||||
"v12-proof-of-spacetime-rational-ba14a058a9dea194f68596f8ecf6537074f038a15c8d1a8550e10e31d4728912.params": {
|
||||
"cid": "QmZBvF2F9wTYKLBxWSCQKe34D3M7vkNNc7ou8mxnNhZkZc",
|
||||
"digest": "5d854e0ecfbd12cb7fa1247a6e6a0315",
|
||||
"v14-proof-of-spacetime-rational-ba14a058a9dea194f68596f8ecf6537074f038a15c8d1a8550e10e31d4728912.params": {
|
||||
"cid": "QmYNVRVzjXkuxJfnHTU5vmEcUBQf8dabXZ4m53SzqMkBv5",
|
||||
"digest": "d156b685e4a1fe3a1f7230b6a39b5ad4",
|
||||
"sector_size": 1024
|
||||
},
|
||||
"v12-proof-of-spacetime-rational-ba14a058a9dea194f68596f8ecf6537074f038a15c8d1a8550e10e31d4728912.vk": {
|
||||
"cid": "QmZfdHrnk2oN3Gx7hhjpRGXu8qY6FcqLjpHQ6jt1BBDg5R",
|
||||
"digest": "aca566faa466f05fb9d622bec39e4b6d",
|
||||
"v14-proof-of-spacetime-rational-ba14a058a9dea194f68596f8ecf6537074f038a15c8d1a8550e10e31d4728912.vk": {
|
||||
"cid": "QmaCEcsCFVuepMKdC5WURbr5ucEyLMNGxQaB7HqSnr2KGh",
|
||||
"digest": "06ff067ac78cdab5d7bbc82170882241",
|
||||
"sector_size": 1024
|
||||
},
|
||||
"v12-proof-of-spacetime-rational-c2ae2b440e693ee69fd6da9e85c4294c5c70c1a46d5785ca5f2a676d6cd4c8de.params": {
|
||||
"cid": "QmYdGGwQXpaBGTVWXqMFVXUP2CZhtsV29jxPkRm54ArAdT",
|
||||
"digest": "eb2d3c4cb7b32c87ead5326bcbd495f3",
|
||||
"v14-proof-of-spacetime-rational-c2ae2b440e693ee69fd6da9e85c4294c5c70c1a46d5785ca5f2a676d6cd4c8de.params": {
|
||||
"cid": "QmVuabRvJ797NwLisGKwRURASGxopBBgg4rfNsbZoSYzAc",
|
||||
"digest": "0e1ceb79a459a60508f480e5b1fed7ac",
|
||||
"sector_size": 268435456
|
||||
},
|
||||
"v12-proof-of-spacetime-rational-c2ae2b440e693ee69fd6da9e85c4294c5c70c1a46d5785ca5f2a676d6cd4c8de.vk": {
|
||||
"cid": "QmeTtWQ2hCUq34BpHTy21jJqVqHbPJdNhQRqW4SF4ZNA7v",
|
||||
"digest": "c83eca165ba94233861227578d658a22",
|
||||
"v14-proof-of-spacetime-rational-c2ae2b440e693ee69fd6da9e85c4294c5c70c1a46d5785ca5f2a676d6cd4c8de.vk": {
|
||||
"cid": "QmdWENZBAbuUty1vVNn9vmvj1XbJ5UC8qzpcVD35s5AJxG",
|
||||
"digest": "1b755c74b9d6823c014f6a7ef76249f2",
|
||||
"sector_size": 268435456
|
||||
},
|
||||
"v12-zigzag-proof-of-replication-0ed875801b4a99e4a6b46e58703e6857277ce020510fc9080041f6cfd5e0d286.params": {
|
||||
"cid": "QmTkeyz3mfec4MqCbbiwuVWAQicY231zpdxSjdxN5U84PD",
|
||||
"digest": "cf7118ac2273e2ccb6b451a5acd5f6e0",
|
||||
"sector_size": 1073741824
|
||||
},
|
||||
"v12-zigzag-proof-of-replication-0ed875801b4a99e4a6b46e58703e6857277ce020510fc9080041f6cfd5e0d286.vk": {
|
||||
"cid": "QmaGzJCwJNpQAD63QAKb8y4MKS1AMHeKyYzg3C5WyRSRRM",
|
||||
"digest": "288c792f4fe09c85f8f35673fb9d5ed0",
|
||||
"sector_size": 1073741824
|
||||
},
|
||||
"v12-zigzag-proof-of-replication-5efcf852a15bd74808bc65d6f2df146de817baea96c96e3b752e6a3349957644.params": {
|
||||
"cid": "QmNSuxq15JPFCTehxVpgJydNZ79rpLoNwnLzQMGA9EziXg",
|
||||
"digest": "818cd9cc2e0e47210a05bd073847ab5a",
|
||||
"sector_size": 268435456
|
||||
},
|
||||
"v12-zigzag-proof-of-replication-5efcf852a15bd74808bc65d6f2df146de817baea96c96e3b752e6a3349957644.vk": {
|
||||
"cid": "Qmbc8LcydZXsVqQrkNMeLEu31Vxi1VigQGJ2ehytxWPALH",
|
||||
"digest": "a6636e2ee1a176161e022296bc045e79",
|
||||
"sector_size": 268435456
|
||||
},
|
||||
"v12-zigzag-proof-of-replication-6496c180c2eab89ee0638bc73879ced01daf512486eb38b9e1c9402ba578e010.params": {
|
||||
"cid": "QmUBpwbVwu5uzjTS8n1yesJ2QUaVbWJ8D9p2VaSsfjgAUr",
|
||||
"digest": "e7aa73a1b06290d30f567bfac8324bf1",
|
||||
"v14-stacked-proof-of-replication-0c0b444c6f31d11c8e98003cc99a3b938db26b77a296d4253cda8945c234266d.params": {
|
||||
"cid": "QmPG38HmDNVFiQJskqKe9sfSjyHfvZRihcfry78rt22FDT",
|
||||
"digest": "8ea0b47e72250d5d6dab5d4f859e65de",
|
||||
"sector_size": 16777216
|
||||
},
|
||||
"v12-zigzag-proof-of-replication-6496c180c2eab89ee0638bc73879ced01daf512486eb38b9e1c9402ba578e010.vk": {
|
||||
"cid": "Qme2uK8sQJUT3DzF291p2b91eFQzn7cKSJFiKVBsvrjTgt",
|
||||
"digest": "d318cd116803c8ccbd3ac4cded9400ad",
|
||||
"v14-stacked-proof-of-replication-0c0b444c6f31d11c8e98003cc99a3b938db26b77a296d4253cda8945c234266d.vk": {
|
||||
"cid": "Qmd3pNM22pgAoRT24tNyEZmeEWK2GtoZznBvzjie2YgqCn",
|
||||
"digest": "e39f344757c919ae6bbc9b61311c73b2",
|
||||
"sector_size": 16777216
|
||||
},
|
||||
"v12-zigzag-proof-of-replication-a09b5cf44f640589b1b02cf823fa28269850342bcefa4878189b9b5c9ec4d2bb.params": {
|
||||
"cid": "QmTfhTnkFvbpFfw8UydFdnPCDfxgAxEcw4fRdGsELpcFnh",
|
||||
"digest": "906b6c0c9dc5bb581d9641c11b54e197",
|
||||
"v14-stacked-proof-of-replication-967b11bb59be11b7dc6f2b627520ba450a3aa50846dbbf886cb8b735fe25c4e7.params": {
|
||||
"cid": "QmQsS6RqWmgdwPnHCwhBJH3WDPcAxhKfbQUs2bwa8D9su8",
|
||||
"digest": "09879a69abcc51de5c1095f347c84e2b",
|
||||
"sector_size": 268435456
|
||||
},
|
||||
"v14-stacked-proof-of-replication-967b11bb59be11b7dc6f2b627520ba450a3aa50846dbbf886cb8b735fe25c4e7.vk": {
|
||||
"cid": "QmSFBL5rg2TJv8QjLzrbr4c2KV2uDNN13RBVNUgwemJgM1",
|
||||
"digest": "db0f245f7e9989879d2fa6328bd57d32",
|
||||
"sector_size": 268435456
|
||||
},
|
||||
"v14-stacked-proof-of-replication-d01cd22091627b721c60a3375b5219af653fb9f6928c70aa7400587d396bc07a.params": {
|
||||
"cid": "QmZ9UVBfviaNFsKyazA4k8GZcM1tHNDpDyrEK9qkxaMJXx",
|
||||
"digest": "402a7c7c82eaa4af9fba3c7e4402b65b",
|
||||
"sector_size": 1073741824
|
||||
},
|
||||
"v14-stacked-proof-of-replication-d01cd22091627b721c60a3375b5219af653fb9f6928c70aa7400587d396bc07a.vk": {
|
||||
"cid": "QmNmDcPVJ1bFFDcNCcRnEoQ6vNDNpKadLPHyEpUoF47gxV",
|
||||
"digest": "2741c456346a3758e88249d1f4c0d227",
|
||||
"sector_size": 1073741824
|
||||
},
|
||||
"v14-stacked-proof-of-replication-f464b92d805d03de6e2c20e2530135b2c8ec96045ec58f342d6feb90282bff8a.params": {
|
||||
"cid": "QmNqgCv6UjdKDNMuiwDweZ22TQYMd3gV6nWiA5PjMtNDVu",
|
||||
"digest": "a9d316d0dbca152e653d41ad8e40058a",
|
||||
"sector_size": 1024
|
||||
},
|
||||
"v12-zigzag-proof-of-replication-a09b5cf44f640589b1b02cf823fa28269850342bcefa4878189b9b5c9ec4d2bb.vk": {
|
||||
"cid": "QmRDcUxfpPY9a1vR3T4vRgxHtWHyy9m3xuMQtj8P749r4e",
|
||||
"digest": "3632776cd23e376694c625390b9a73ea",
|
||||
"v14-stacked-proof-of-replication-f464b92d805d03de6e2c20e2530135b2c8ec96045ec58f342d6feb90282bff8a.vk": {
|
||||
"cid": "QmTGQGThNFEjaMFgP32YLubACrtpkRoeVEfhDaWi5g6w8u",
|
||||
"digest": "021b3e81e2980a50fd1ac07424d29a8d",
|
||||
"sector_size": 1024
|
||||
}
|
||||
}
|
||||
}
|
@ -162,7 +162,7 @@ func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams)
|
||||
|
||||
func IsBuiltinActor(code cid.Cid) bool {
|
||||
switch code {
|
||||
case StorageMarketActorCodeCid, StorageMinerCodeCid, AccountActorCodeCid, InitActorCodeCid, MultisigActorCodeCid, PaymentChannelActorCodeCid:
|
||||
case StorageMarketCodeCid, StoragePowerCodeCid, StorageMinerCodeCid, AccountCodeCid, InitCodeCid, MultisigCodeCid, PaymentChannelCodeCid:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
@ -170,12 +170,11 @@ func IsBuiltinActor(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) {
|
||||
nid := ias.NextID
|
||||
ias.NextID++
|
||||
|
||||
amap, err := hamt.LoadNode(context.TODO(), cst, ias.AddressMap)
|
||||
if err != nil {
|
||||
@ -195,6 +194,7 @@ func (ias *InitActorState) AddActor(cst *hamt.CborIpldStore, addr address.Addres
|
||||
return address.Undef, err
|
||||
}
|
||||
ias.AddressMap = ncid
|
||||
ias.NextID++
|
||||
|
||||
return NewIDAddress(nid)
|
||||
}
|
||||
|
@ -18,8 +18,6 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
const POST_SECTORS_COUNT = 8192
|
||||
|
||||
type StorageMinerActor struct{}
|
||||
|
||||
type StorageMinerActorState struct {
|
||||
@ -89,40 +87,38 @@ type MinerInfo struct {
|
||||
PeerID peer.ID
|
||||
|
||||
// Amount of space in each sector committed to the network by this miner.
|
||||
SectorSize types.BigInt
|
||||
SectorSize uint64
|
||||
}
|
||||
|
||||
type StorageMinerConstructorParams struct {
|
||||
Owner address.Address
|
||||
Worker address.Address
|
||||
SectorSize types.BigInt
|
||||
SectorSize uint64
|
||||
PeerID peer.ID
|
||||
}
|
||||
|
||||
type maMethods struct {
|
||||
Constructor uint64
|
||||
CommitSector uint64
|
||||
SubmitPoSt uint64
|
||||
SlashStorageFault uint64
|
||||
GetCurrentProvingSet uint64
|
||||
ArbitrateDeal uint64
|
||||
DePledge uint64
|
||||
GetOwner uint64
|
||||
GetWorkerAddr uint64
|
||||
GetPower uint64
|
||||
GetPeerID uint64
|
||||
GetSectorSize uint64
|
||||
UpdatePeerID uint64
|
||||
ChangeWorker uint64
|
||||
IsSlashed uint64
|
||||
IsLate uint64
|
||||
PaymentVerifyInclusion uint64
|
||||
PaymentVerifySector uint64
|
||||
AddFaults uint64
|
||||
SlashConsensusFault uint64
|
||||
Constructor uint64
|
||||
CommitSector uint64
|
||||
SubmitPoSt uint64
|
||||
SlashStorageFault uint64
|
||||
GetCurrentProvingSet uint64
|
||||
ArbitrateDeal uint64
|
||||
DePledge uint64
|
||||
GetOwner uint64
|
||||
GetWorkerAddr uint64
|
||||
GetPower uint64
|
||||
GetPeerID uint64
|
||||
GetSectorSize uint64
|
||||
UpdatePeerID uint64
|
||||
ChangeWorker uint64
|
||||
IsSlashed uint64
|
||||
IsLate 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{} {
|
||||
return []interface{}{
|
||||
@ -142,10 +138,8 @@ func (sma StorageMinerActor) Exports() []interface{} {
|
||||
//14: sma.ChangeWorker,
|
||||
//15: sma.IsSlashed,
|
||||
//16: sma.IsLate,
|
||||
17: sma.PaymentVerifyInclusion,
|
||||
18: sma.PaymentVerifySector,
|
||||
19: sma.AddFaults,
|
||||
20: sma.SlashConsensusFault,
|
||||
17: sma.AddFaults,
|
||||
18: sma.SlashConsensusFault,
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,15 +199,17 @@ func (sma StorageMinerActor) StorageMinerConstructor(act *types.Actor, vmctx typ
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type CommitSectorParams struct {
|
||||
SectorID uint64
|
||||
CommD []byte
|
||||
CommR []byte
|
||||
CommRStar []byte
|
||||
Proof []byte
|
||||
type OnChainSealVerifyInfo struct {
|
||||
CommD []byte // TODO: update proofs code
|
||||
CommR []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()
|
||||
oldstate, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
@ -225,36 +221,46 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if vmctx.Message().From != mi.Worker {
|
||||
return nil, aerrors.New(1, "not authorized to commit sector for miner")
|
||||
}
|
||||
|
||||
// TODO: this needs to get normalized to either the ID address or the actor address
|
||||
maddr := vmctx.Message().To
|
||||
|
||||
if ok, err := ValidatePoRep(maddr, mi.SectorSize, params); err != nil {
|
||||
ticket, err := vmctx.GetRandomness(params.Epoch)
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrap(err, "failed to get randomness for commitsector")
|
||||
}
|
||||
|
||||
if ok, err := ValidatePoRep(maddr, mi.SectorSize, params, ticket); err != nil {
|
||||
return nil, err
|
||||
} else if !ok {
|
||||
return nil, aerrors.New(1, "bad proof!")
|
||||
return nil, aerrors.New(2, "bad proof!")
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return nil, err
|
||||
}
|
||||
if !unique {
|
||||
return nil, aerrors.New(2, "sector already committed!")
|
||||
return nil, aerrors.New(3, "sector already committed!")
|
||||
}
|
||||
|
||||
// Power of the miner after adding this sector
|
||||
futurePower := types.BigAdd(self.Power, mi.SectorSize)
|
||||
futurePower := types.BigAdd(self.Power, types.NewInt(mi.SectorSize))
|
||||
collateralRequired := CollateralForPower(futurePower)
|
||||
|
||||
// TODO: grab from market?
|
||||
if act.Balance.LessThan(collateralRequired) {
|
||||
return nil, aerrors.New(3, "not enough collateral")
|
||||
return nil, aerrors.New(4, "not enough collateral")
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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 {
|
||||
return nil, err
|
||||
}
|
||||
@ -286,7 +292,15 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex
|
||||
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 {
|
||||
@ -346,7 +360,7 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext,
|
||||
|
||||
var seed [sectorbuilder.CommLen]byte
|
||||
{
|
||||
randHeight := currentProvingPeriodEnd - build.PoSTChallangeTime
|
||||
randHeight := currentProvingPeriodEnd - build.PoStChallangeTime - build.PoStRandomnessLookback
|
||||
if vmctx.BlockHeight() <= randHeight {
|
||||
// TODO: spec, retcode
|
||||
return nil, aerrors.Newf(1, "submit PoSt called outside submission window (%d < %d)", vmctx.BlockHeight(), randHeight)
|
||||
@ -393,7 +407,7 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext,
|
||||
|
||||
faults := self.CurrentFaultSet.All()
|
||||
|
||||
if ok, lerr := sectorbuilder.VerifyPost(mi.SectorSize.Uint64(),
|
||||
if ok, lerr := sectorbuilder.VerifyPost(mi.SectorSize,
|
||||
sectorbuilder.NewSortedSectorInfo(sectorInfos), seed, params.Proof,
|
||||
faults); !ok || lerr != nil {
|
||||
if lerr != nil {
|
||||
@ -426,14 +440,14 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext,
|
||||
|
||||
oldPower := self.Power
|
||||
self.Power = types.BigMul(types.NewInt(pss.Count-uint64(len(faults))),
|
||||
mi.SectorSize)
|
||||
types.NewInt(mi.SectorSize))
|
||||
|
||||
enc, err := SerializeParams(&UpdateStorageParams{Delta: types.BigSub(self.Power, oldPower)})
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@ -511,8 +525,8 @@ func GetFromSectorSet(ctx context.Context, s types.Storage, ss cid.Cid, sectorID
|
||||
return true, comms[0], comms[1], nil
|
||||
}
|
||||
|
||||
func ValidatePoRep(maddr address.Address, ssize types.BigInt, params *CommitSectorParams) (bool, ActorError) {
|
||||
ok, err := sectorbuilder.VerifySeal(ssize.Uint64(), params.CommR, params.CommD, params.CommRStar, maddr, params.SectorID, params.Proof)
|
||||
func ValidatePoRep(maddr address.Address, ssize uint64, params *OnChainSealVerifyInfo, ticket []byte) (bool, ActorError) {
|
||||
ok, err := sectorbuilder.VerifySeal(ssize, params.CommR, params.CommD, maddr, ticket, params.SectorNumber, params.Proof)
|
||||
if err != nil {
|
||||
return false, aerrors.Absorb(err, 25, "verify seal failed")
|
||||
}
|
||||
@ -626,7 +640,7 @@ func (sma StorageMinerActor) GetSectorSize(act *types.Actor, vmctx types.VMConte
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mi.SectorSize.Bytes(), nil
|
||||
return types.NewInt(mi.SectorSize).Bytes(), nil
|
||||
}
|
||||
|
||||
type PaymentVerifyParams struct {
|
||||
@ -634,84 +648,6 @@ type PaymentVerifyParams struct {
|
||||
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 {
|
||||
Faults types.BitField
|
||||
}
|
||||
@ -722,7 +658,7 @@ func (sma StorageMinerActor) AddFaults(act *types.Actor, vmctx types.VMContext,
|
||||
return nil, aerr
|
||||
}
|
||||
|
||||
challengeHeight := self.ProvingPeriodEnd - build.PoSTChallangeTime
|
||||
challengeHeight := self.ProvingPeriodEnd - build.PoStChallangeTime
|
||||
|
||||
if vmctx.BlockHeight() < challengeHeight {
|
||||
// TODO: optimized bitfield methods
|
||||
@ -753,7 +689,7 @@ type MinerSlashConsensusFault struct {
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
|
@ -16,10 +16,29 @@ type MultiSigActorState struct {
|
||||
Required uint64
|
||||
NextTxID uint64
|
||||
|
||||
InitialBalance types.BigInt
|
||||
StartingBlock uint64
|
||||
UnlockDuration uint64
|
||||
|
||||
//TODO: make this map/sharray/whatever
|
||||
Transactions []MTransaction
|
||||
}
|
||||
|
||||
func (msas MultiSigActorState) canSpend(act *types.Actor, amnt types.BigInt, height uint64) bool {
|
||||
if msas.UnlockDuration == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
offset := height - msas.StartingBlock
|
||||
if offset > msas.UnlockDuration {
|
||||
return true
|
||||
}
|
||||
|
||||
minBalance := types.BigDiv(msas.InitialBalance, types.NewInt(msas.UnlockDuration))
|
||||
minBalance = types.BigMul(minBalance, types.NewInt(offset))
|
||||
return !minBalance.LessThan(types.BigSub(act.Balance, amnt))
|
||||
}
|
||||
|
||||
func (msas MultiSigActorState) isSigner(addr address.Address) bool {
|
||||
for _, s := range msas.Signers {
|
||||
if s == addr {
|
||||
@ -90,8 +109,9 @@ func (msa MultiSigActor) Exports() []interface{} {
|
||||
}
|
||||
|
||||
type MultiSigConstructorParams struct {
|
||||
Signers []address.Address
|
||||
Required uint64
|
||||
Signers []address.Address
|
||||
Required uint64
|
||||
UnlockDuration uint64
|
||||
}
|
||||
|
||||
func (MultiSigActor) MultiSigConstructor(act *types.Actor, vmctx types.VMContext,
|
||||
@ -100,6 +120,13 @@ func (MultiSigActor) MultiSigConstructor(act *types.Actor, vmctx types.VMContext
|
||||
Signers: params.Signers,
|
||||
Required: params.Required,
|
||||
}
|
||||
|
||||
if params.UnlockDuration != 0 {
|
||||
self.InitialBalance = vmctx.Message().Value
|
||||
self.UnlockDuration = params.UnlockDuration
|
||||
self.StartingBlock = vmctx.BlockHeight()
|
||||
}
|
||||
|
||||
head, err := vmctx.Storage().Put(self)
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrap(err, "could not put new head")
|
||||
@ -183,6 +210,9 @@ func (msa MultiSigActor) Propose(act *types.Actor, vmctx types.VMContext,
|
||||
}
|
||||
|
||||
if self.Required == 1 {
|
||||
if !self.canSpend(act, tx.Value, vmctx.BlockHeight()) {
|
||||
return nil, aerrors.New(100, "transaction amount exceeds available")
|
||||
}
|
||||
_, err := vmctx.Send(tx.To, tx.Method, tx.Value, tx.Params)
|
||||
if aerrors.IsFatal(err) {
|
||||
return nil, err
|
||||
@ -229,6 +259,9 @@ func (msa MultiSigActor) Approve(act *types.Actor, vmctx types.VMContext,
|
||||
}
|
||||
tx.Approved = append(tx.Approved, vmctx.Message().From)
|
||||
if uint64(len(tx.Approved)) >= self.Required {
|
||||
if !self.canSpend(act, tx.Value, vmctx.BlockHeight()) {
|
||||
return nil, aerrors.New(100, "transaction amount exceeds available")
|
||||
}
|
||||
_, err := vmctx.Send(tx.To, tx.Method, tx.Value, tx.Params)
|
||||
if aerrors.IsFatal(err) {
|
||||
return nil, err
|
||||
|
@ -23,7 +23,7 @@ func TestMultiSigCreate(t *testing.T) {
|
||||
}
|
||||
|
||||
h := NewHarness(t, opts...)
|
||||
ret, _ := h.CreateActor(t, creatorAddr, actors.MultisigActorCodeCid,
|
||||
ret, _ := h.CreateActor(t, creatorAddr, actors.MultisigCodeCid,
|
||||
&actors.MultiSigConstructorParams{
|
||||
Signers: []address.Address{creatorAddr, sig1Addr, sig2Addr},
|
||||
Required: 2,
|
||||
@ -49,7 +49,7 @@ func TestMultiSigOps(t *testing.T) {
|
||||
HarnessAddr(&sig1Addr, 100000),
|
||||
HarnessAddr(&sig2Addr, 100000),
|
||||
HarnessAddr(&outsideAddr, 100000),
|
||||
HarnessActor(&multSigAddr, &creatorAddr, actors.MultisigActorCodeCid,
|
||||
HarnessActor(&multSigAddr, &creatorAddr, actors.MultisigCodeCid,
|
||||
func() cbg.CBORMarshaler {
|
||||
return &actors.MultiSigConstructorParams{
|
||||
Signers: []address.Address{creatorAddr, sig1Addr, sig2Addr},
|
||||
|
@ -18,7 +18,7 @@ func TestPaychCreate(t *testing.T) {
|
||||
}
|
||||
|
||||
h := NewHarness(t, opts...)
|
||||
ret, _ := h.CreateActor(t, creatorAddr, actors.PaymentChannelActorCodeCid,
|
||||
ret, _ := h.CreateActor(t, creatorAddr, actors.PaymentChannelCodeCid,
|
||||
&actors.PCAConstructorParams{
|
||||
To: targetAddr,
|
||||
})
|
||||
@ -47,7 +47,7 @@ func TestPaychUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
h := NewHarness(t, opts...)
|
||||
ret, _ := h.CreateActor(t, creatorAddr, actors.PaymentChannelActorCodeCid,
|
||||
ret, _ := h.CreateActor(t, creatorAddr, actors.PaymentChannelCodeCid,
|
||||
&actors.PCAConstructorParams{
|
||||
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
|
||||
|
||||
StoragePricePerEpoch types.BigInt
|
||||
StorageCollateral types.BigInt
|
||||
|
||||
ProposerSignature *types.Signature
|
||||
}
|
||||
|
||||
func (sdp *StorageDealProposal) TotalStoragePrice() types.BigInt {
|
||||
return types.BigMul(sdp.StoragePricePerEpoch, types.NewInt(sdp.Duration))
|
||||
}
|
||||
|
||||
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]
|
||||
|
||||
totalPrice := deal.Proposal.TotalStoragePrice()
|
||||
|
||||
if clientBalance.Available.LessThan(totalPrice) {
|
||||
return aerrors.Newf(5, "client doesn't have enough available funds to cover storage price; %d < %d", clientBalance.Available, totalPrice)
|
||||
}
|
||||
|
||||
clientBalance = lockFunds(clientBalance, totalPrice)
|
||||
|
||||
// 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.BigMul(dealInfo.Deal.Proposal.StoragePricePerEpoch, types.NewInt(build.ProvingPeriodDuration))
|
||||
|
||||
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) {
|
||||
|
||||
}
|
||||
*/
|
@ -53,12 +53,12 @@ type StoragePowerState struct {
|
||||
type CreateStorageMinerParams struct {
|
||||
Owner address.Address
|
||||
Worker address.Address
|
||||
SectorSize types.BigInt
|
||||
SectorSize uint64
|
||||
PeerID peer.ID
|
||||
}
|
||||
|
||||
func (spa StoragePowerActor) CreateStorageMiner(act *types.Actor, vmctx types.VMContext, params *CreateStorageMinerParams) ([]byte, ActorError) {
|
||||
if !SupportedSectorSize(params.SectorSize) {
|
||||
if !build.SupportedSectorSize(params.SectorSize) {
|
||||
return nil, aerrors.New(1, "Unsupported sector size")
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ func (spa StoragePowerActor) CreateStorageMiner(act *types.Actor, vmctx types.VM
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@ -116,13 +116,6 @@ func (spa StoragePowerActor) CreateStorageMiner(act *types.Actor, vmctx types.VM
|
||||
return naddr.Bytes(), nil
|
||||
}
|
||||
|
||||
func SupportedSectorSize(ssize types.BigInt) bool {
|
||||
if ssize.Uint64() == build.SectorSize {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ArbitrateConsensusFaultParams struct {
|
||||
Block1 *types.BlockHeader
|
||||
Block2 *types.BlockHeader
|
||||
|
@ -37,12 +37,12 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) {
|
||||
// cheating the bootstrapping problem
|
||||
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),
|
||||
&CreateStorageMinerParams{
|
||||
Owner: ownerAddr,
|
||||
Worker: workerAddr,
|
||||
SectorSize: types.NewInt(build.SectorSize),
|
||||
SectorSize: build.SectorSizes[0],
|
||||
PeerID: "fakepeerid",
|
||||
})
|
||||
ApplyOK(t, ret)
|
||||
@ -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})
|
||||
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})
|
||||
ApplyOK(t, ret)
|
||||
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, b2)
|
||||
|
||||
ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SPAMethods.ArbitrateConsensusFault,
|
||||
ret, _ := h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.ArbitrateConsensusFault,
|
||||
&ArbitrateConsensusFaultParams{
|
||||
Block1: b1,
|
||||
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})
|
||||
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)
|
||||
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) {
|
||||
t.Helper()
|
||||
|
||||
sma, err := vm.StateTree().GetActor(StorageMarketAddress)
|
||||
sma, err := vm.StateTree().GetActor(StoragePowerAddress)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -138,7 +138,7 @@ func cheatStorageMarketTotal(t *testing.T, vm *vm.VM, bs bstore.Blockstore) {
|
||||
|
||||
sma.Head = c
|
||||
|
||||
if err := vm.StateTree().SetActor(StorageMarketAddress, sma); err != nil {
|
||||
if err := vm.StateTree().SetActor(StoragePowerAddress, sma); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -7,16 +7,18 @@ import (
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
)
|
||||
|
||||
var AccountActorCodeCid cid.Cid
|
||||
var StorageMarketActorCodeCid cid.Cid
|
||||
var AccountCodeCid cid.Cid
|
||||
var StoragePowerCodeCid cid.Cid
|
||||
var StorageMarketCodeCid cid.Cid
|
||||
var StorageMinerCodeCid cid.Cid
|
||||
var MultisigActorCodeCid cid.Cid
|
||||
var InitActorCodeCid cid.Cid
|
||||
var PaymentChannelActorCodeCid cid.Cid
|
||||
var MultisigCodeCid cid.Cid
|
||||
var InitCodeCid cid.Cid
|
||||
var PaymentChannelCodeCid cid.Cid
|
||||
|
||||
var InitActorAddress = mustIDAddress(0)
|
||||
var InitAddress = mustIDAddress(0)
|
||||
var NetworkAddress = mustIDAddress(1)
|
||||
var StorageMarketAddress = mustIDAddress(2)
|
||||
var StoragePowerAddress = mustIDAddress(2)
|
||||
var StorageMarketAddress = mustIDAddress(3) // TODO: missing from spec
|
||||
var BurntFundsAddress = mustIDAddress(99)
|
||||
|
||||
func mustIDAddress(i uint64) address.Address {
|
||||
@ -37,10 +39,11 @@ func init() {
|
||||
return c
|
||||
}
|
||||
|
||||
AccountActorCodeCid = mustSum("account")
|
||||
StorageMarketActorCodeCid = mustSum("smarket")
|
||||
StorageMinerCodeCid = mustSum("sminer")
|
||||
MultisigActorCodeCid = mustSum("multisig")
|
||||
InitActorCodeCid = mustSum("init")
|
||||
PaymentChannelActorCodeCid = mustSum("paych")
|
||||
AccountCodeCid = mustSum("fil/1/account") // TODO: spec
|
||||
StoragePowerCodeCid = mustSum("fil/1/power")
|
||||
StorageMarketCodeCid = mustSum("fil/1/market")
|
||||
StorageMinerCodeCid = mustSum("fil/1/miner")
|
||||
MultisigCodeCid = mustSum("fil/1/multisig")
|
||||
InitCodeCid = mustSum("fil/1/init")
|
||||
PaymentChannelCodeCid = mustSum("fil/1/paych")
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ func TestVMInvokeMethod(t *testing.T) {
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
To: InitActorAddress,
|
||||
To: InitAddress,
|
||||
From: from,
|
||||
Method: IAMethods.Exec,
|
||||
Params: enc,
|
||||
@ -118,7 +118,7 @@ func TestStorageMarketActorCreateMiner(t *testing.T) {
|
||||
params := &StorageMinerConstructorParams{
|
||||
Owner: maddr,
|
||||
Worker: maddr,
|
||||
SectorSize: types.NewInt(build.SectorSize),
|
||||
SectorSize: build.SectorSizes[0],
|
||||
PeerID: "fakepeerid",
|
||||
}
|
||||
var err error
|
||||
@ -128,7 +128,7 @@ func TestStorageMarketActorCreateMiner(t *testing.T) {
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
To: StorageMarketAddress,
|
||||
To: StoragePowerAddress,
|
||||
From: from,
|
||||
Method: SPAMethods.CreateStorageMiner,
|
||||
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()
|
||||
|
||||
return h.Apply(t, types.Message{
|
||||
To: actors.InitActorAddress,
|
||||
To: actors.InitAddress,
|
||||
From: from,
|
||||
Method: actors.IAMethods.Exec,
|
||||
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.PricePerEpoch (types.BigInt)
|
||||
if err := t.PricePerEpoch.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.PricePerEpoch (types.BigInt)
|
||||
|
||||
{
|
||||
|
||||
if err := t.PricePerEpoch.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 (
|
||||
"context"
|
||||
"math"
|
||||
"github.com/filecoin-project/lotus/node/impl/full"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/namespace"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log"
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
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/address"
|
||||
"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/wallet"
|
||||
"github.com/filecoin-project/lotus/lib/cborrpc"
|
||||
@ -25,22 +25,11 @@ import (
|
||||
"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")
|
||||
|
||||
type ClientDeal struct {
|
||||
ProposalCid cid.Cid
|
||||
Proposal StorageDealProposal
|
||||
Proposal actors.StorageDealProposal
|
||||
State api.DealState
|
||||
Miner peer.ID
|
||||
|
||||
@ -49,15 +38,17 @@ type ClientDeal struct {
|
||||
|
||||
type Client struct {
|
||||
sm *stmgr.StateManager
|
||||
chain *store.ChainStore
|
||||
h host.Host
|
||||
w *wallet.Wallet
|
||||
dag dtypes.ClientDAG
|
||||
discovery *discovery.Local
|
||||
mpool full.MpoolAPI
|
||||
|
||||
deals ClientStateStore
|
||||
conns map[cid.Cid]inet.Stream
|
||||
|
||||
incoming chan ClientDeal
|
||||
incoming chan *ClientDeal
|
||||
updated chan clientDealUpdate
|
||||
|
||||
stop chan struct{}
|
||||
@ -70,18 +61,20 @@ type clientDealUpdate struct {
|
||||
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{
|
||||
sm: sm,
|
||||
chain: chain,
|
||||
h: h,
|
||||
w: w,
|
||||
dag: dag,
|
||||
discovery: discovery,
|
||||
mpool: mpool,
|
||||
|
||||
deals: ClientStateStore{StateStore{ds: namespace.Wrap(ds, datastore.NewKey("/deals/client"))}},
|
||||
conns: map[cid.Cid]inet.Stream{},
|
||||
|
||||
incoming: make(chan ClientDeal, 16),
|
||||
incoming: make(chan *ClientDeal, 16),
|
||||
updated: make(chan clientDealUpdate, 16),
|
||||
|
||||
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")
|
||||
|
||||
if _, ok := c.conns[deal.ProposalCid]; ok {
|
||||
@ -166,70 +159,94 @@ func (c *Client) onUpdated(ctx context.Context, update clientDealUpdate) {
|
||||
type ClientDealProposal struct {
|
||||
Data cid.Cid
|
||||
|
||||
TotalPrice types.BigInt
|
||||
Duration uint64
|
||||
PricePerEpoch types.BigInt
|
||||
ProposalExpiration uint64
|
||||
Duration uint64
|
||||
|
||||
Payment actors.PaymentInfo
|
||||
|
||||
MinerAddress address.Address
|
||||
ClientAddress address.Address
|
||||
MinerID peer.ID
|
||||
ProviderAddress address.Address
|
||||
Client address.Address
|
||||
MinerID peer.ID
|
||||
}
|
||||
|
||||
func (c *Client) VerifyParams(ctx context.Context, data cid.Cid) (*actors.PieceInclVoucherData, error) {
|
||||
commP, size, err := c.commP(ctx, data)
|
||||
func (c *Client) Start(ctx context.Context, p ClientDealProposal) (cid.Cid, error) {
|
||||
// check market funds
|
||||
clientMarketBalance, err := c.sm.MarketBalance(ctx, p.Client, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return cid.Undef, xerrors.Errorf("getting client market balance failed: %w", err)
|
||||
}
|
||||
|
||||
return &actors.PieceInclVoucherData{
|
||||
CommP: commP,
|
||||
PieceSize: types.NewInt(uint64(size)),
|
||||
}, nil
|
||||
}
|
||||
if clientMarketBalance.Available.LessThan(types.BigMul(p.PricePerEpoch, types.NewInt(p.Duration))) {
|
||||
// TODO: move to a smarter market funds manager
|
||||
|
||||
func (c *Client) Start(ctx context.Context, p ClientDealProposal, vd *actors.PieceInclVoucherData) (cid.Cid, error) {
|
||||
proposal := StorageDealProposal{
|
||||
PieceRef: p.Data,
|
||||
SerializationMode: SerializationUnixFs,
|
||||
CommP: vd.CommP[:],
|
||||
Size: vd.PieceSize.Uint64(),
|
||||
TotalPrice: p.TotalPrice,
|
||||
Duration: p.Duration,
|
||||
Payment: p.Payment,
|
||||
MinerAddress: p.MinerAddress,
|
||||
ClientAddress: p.ClientAddress,
|
||||
smsg, err := c.mpool.MpoolPushMessage(ctx, &types.Message{
|
||||
To: actors.StorageMarketAddress,
|
||||
From: p.Client,
|
||||
Value: types.BigMul(p.PricePerEpoch, types.NewInt(p.Duration)),
|
||||
GasPrice: types.NewInt(0),
|
||||
GasLimit: types.NewInt(1000000),
|
||||
Method: actors.SMAMethods.AddBalance,
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
_, 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,
|
||||
StoragePricePerEpoch: p.PricePerEpoch,
|
||||
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 {
|
||||
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 {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
proposalNd, err := cbor.WrapObject(proposal, math.MaxUint64, -1)
|
||||
s, err := c.h.NewStream(ctx, p.MinerID, DealProtocolID)
|
||||
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(),
|
||||
Proposal: proposal,
|
||||
Proposal: *proposal,
|
||||
State: api.DealUnknown,
|
||||
Miner: p.MinerID,
|
||||
|
||||
s: s,
|
||||
}
|
||||
|
||||
// TODO: actually care about what happens with the deal after it was accepted
|
||||
c.incoming <- deal
|
||||
|
||||
// TODO: start tracking after the deal is sealed
|
||||
return deal.ProposalCid, c.discovery.AddPeer(p.Data, discovery.RetrievalPeer{
|
||||
Address: proposal.MinerAddress,
|
||||
Address: proposal.Provider,
|
||||
ID: deal.Miner,
|
||||
})
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ package deals
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
)
|
||||
|
||||
type clientHandlerFunc func(ctx context.Context, deal ClientDeal) error
|
||||
@ -39,6 +39,39 @@ func (c *Client) new(ctx context.Context, deal ClientDeal) error {
|
||||
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!")
|
||||
|
||||
return nil
|
||||
@ -75,13 +108,19 @@ func (c *Client) staged(ctx context.Context, deal ClientDeal) error {
|
||||
|
||||
log.Info("DEAL SEALED!")
|
||||
|
||||
ok, err := sectorbuilder.VerifyPieceInclusionProof(build.SectorSize, deal.Proposal.Size, deal.Proposal.CommP, resp.CommD, resp.PieceInclusionProof.ProofElements)
|
||||
// TODO: want?
|
||||
/*ssize, err := stmgr.GetMinerSectorSize(ctx, c.sm, nil, deal.Proposal.MinerAddress)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get miner sector size: %w", err)
|
||||
}
|
||||
|
||||
ok, err := sectorbuilder.VerifyPieceInclusionProof(ssize, deal.Proposal.Size, deal.Proposal.CommP, resp.CommD, resp.PieceInclusionProof.ProofElements)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("verifying piece inclusion proof in staged deal %s: %w", deal.ProposalCid, err)
|
||||
}
|
||||
if !ok {
|
||||
return xerrors.Errorf("verifying piece inclusion proof in staged deal %s failed", deal.ProposalCid)
|
||||
}
|
||||
}*/
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -2,17 +2,13 @@ package deals
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
||||
"runtime"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
files "github.com/ipfs/go-ipfs-files"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
unixfile "github.com/ipfs/go-unixfs/file"
|
||||
inet "github.com/libp2p/go-libp2p-core/network"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/address"
|
||||
"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)
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
log.Errorf("cannot open unixfs file: %s", err)
|
||||
return nil, 0, err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
uf, ok := n.(files.File)
|
||||
if !ok {
|
||||
// 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()
|
||||
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
|
||||
return uf.Size()
|
||||
}
|
||||
|
||||
func (c *Client) sendProposal(s inet.Stream, proposal StorageDealProposal, from address.Address) 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) {
|
||||
func (c *Client) readStorageDealResp(deal ClientDeal) (*Response, error) {
|
||||
s, ok := c.conns[deal.ProposalCid]
|
||||
if !ok {
|
||||
// TODO: Try to re-establish the connection using query protocol
|
||||
return nil, xerrors.Errorf("no connection to miner")
|
||||
}
|
||||
|
||||
var resp SignedStorageDealResponse
|
||||
var resp SignedResponse
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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 (
|
||||
"context"
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
datastore "github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/namespace"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
inet "github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"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/cborrpc"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/storage/commitment"
|
||||
"github.com/filecoin-project/lotus/storage/sectorblocks"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cbor.RegisterCborType(MinerDeal{})
|
||||
}
|
||||
|
||||
type MinerDeal struct {
|
||||
Client peer.ID
|
||||
Proposal StorageDealProposal
|
||||
Proposal actors.StorageDealProposal
|
||||
ProposalCid cid.Cid
|
||||
State api.DealState
|
||||
|
||||
Ref cid.Cid
|
||||
|
||||
DealID uint64
|
||||
SectorID uint64 // Set when State >= DealStaged
|
||||
|
||||
s inet.Stream
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
type Provider struct {
|
||||
pricePerByteBlock types.BigInt // how much we want for storing one byte for one block
|
||||
minPieceSize uint64
|
||||
|
||||
@ -73,7 +70,7 @@ type minerDealUpdate struct {
|
||||
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"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -83,7 +80,7 @@ func NewHandler(ds dtypes.MetadataDS, secst *sectorblocks.SectorBlocks, commt *c
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h := &Handler{
|
||||
h := &Provider{
|
||||
secst: secst,
|
||||
commt: commt,
|
||||
dag: dag,
|
||||
@ -112,7 +109,7 @@ func NewHandler(ds dtypes.MetadataDS, secst *sectorblocks.SectorBlocks, commt *c
|
||||
if h.ask == nil {
|
||||
// TODO: we should be fine with this state, and just say it means 'not actively accepting deals'
|
||||
// for now... lets just set a price
|
||||
if err := h.SetPrice(types.NewInt(3), 1000000); err != nil {
|
||||
if err := h.SetPrice(types.NewInt(500_000_000), 1000000); err != nil {
|
||||
return nil, xerrors.Errorf("failed setting a default price: %w", err)
|
||||
}
|
||||
}
|
||||
@ -120,40 +117,40 @@ func NewHandler(ds dtypes.MetadataDS, secst *sectorblocks.SectorBlocks, commt *c
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (h *Handler) Run(ctx context.Context) {
|
||||
func (p *Provider) Run(ctx context.Context) {
|
||||
// TODO: restore state
|
||||
|
||||
go func() {
|
||||
defer log.Warn("quitting deal handler loop")
|
||||
defer close(h.stopped)
|
||||
defer log.Warn("quitting deal provider loop")
|
||||
defer close(p.stopped)
|
||||
|
||||
for {
|
||||
select {
|
||||
case deal := <-h.incoming: // DealAccepted
|
||||
h.onIncoming(deal)
|
||||
case update := <-h.updated: // DealStaged
|
||||
h.onUpdated(ctx, update)
|
||||
case <-h.stop:
|
||||
case deal := <-p.incoming: // DealAccepted
|
||||
p.onIncoming(deal)
|
||||
case update := <-p.updated: // DealStaged
|
||||
p.onUpdated(ctx, update)
|
||||
case <-p.stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (h *Handler) onIncoming(deal MinerDeal) {
|
||||
func (p *Provider) onIncoming(deal MinerDeal) {
|
||||
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
|
||||
h.failDeal(deal.ProposalCid, err)
|
||||
p.failDeal(deal.ProposalCid, err)
|
||||
log.Errorf("deal tracking failed: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
h.updated <- minerDealUpdate{
|
||||
p.updated <- minerDealUpdate{
|
||||
newState: api.DealAccepted,
|
||||
id: deal.ProposalCid,
|
||||
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)
|
||||
if update.err != nil {
|
||||
log.Errorf("deal %s failed: %s", update.id, update.err)
|
||||
h.failDeal(update.id, update.err)
|
||||
log.Errorf("deal %s (newSt: %d) failed: %s", update.id, update.newState, update.err)
|
||||
p.failDeal(update.id, update.err)
|
||||
return
|
||||
}
|
||||
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
|
||||
if update.mut != nil {
|
||||
update.mut(d)
|
||||
@ -178,30 +175,29 @@ func (h *Handler) onUpdated(ctx context.Context, update minerDealUpdate) {
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
h.failDeal(update.id, err)
|
||||
p.failDeal(update.id, err)
|
||||
return
|
||||
}
|
||||
|
||||
switch update.newState {
|
||||
case api.DealAccepted:
|
||||
h.handle(ctx, deal, h.accept, api.DealStaged)
|
||||
p.handle(ctx, deal, p.accept, api.DealStaged)
|
||||
case api.DealStaged:
|
||||
h.handle(ctx, deal, h.staged, api.DealSealing)
|
||||
p.handle(ctx, deal, p.staged, api.DealSealing)
|
||||
case api.DealSealing:
|
||||
h.handle(ctx, deal, h.sealing, api.DealComplete)
|
||||
p.handle(ctx, deal, p.sealing, 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) {
|
||||
// TODO: Review: Not signed?
|
||||
proposalNd, err := cbor.WrapObject(proposal, math.MaxUint64, -1)
|
||||
func (p *Provider) newDeal(s inet.Stream, proposal actors.StorageDealProposal) (MinerDeal, error) {
|
||||
proposalNd, err := cborrpc.AsIpld(&proposal)
|
||||
if err != nil {
|
||||
return MinerDeal{}, err
|
||||
}
|
||||
|
||||
ref, err := cid.Parse(proposal.PieceRef)
|
||||
ref, err := cid.Cast(proposal.PieceRef)
|
||||
if err != nil {
|
||||
return MinerDeal{}, err
|
||||
}
|
||||
@ -218,27 +214,27 @@ func (h *Handler) newDeal(s inet.Stream, proposal StorageDealProposal) (MinerDea
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *Handler) HandleStream(s inet.Stream) {
|
||||
func (p *Provider) HandleStream(s inet.Stream) {
|
||||
log.Info("Handling storage deal proposal!")
|
||||
|
||||
proposal, err := h.readProposal(s)
|
||||
proposal, err := p.readProposal(s)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
s.Close()
|
||||
return
|
||||
}
|
||||
|
||||
deal, err := h.newDeal(s, proposal.Proposal)
|
||||
deal, err := p.newDeal(s, proposal)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
s.Close()
|
||||
return
|
||||
}
|
||||
|
||||
h.incoming <- deal
|
||||
p.incoming <- deal
|
||||
}
|
||||
|
||||
func (h *Handler) Stop() {
|
||||
close(h.stop)
|
||||
<-h.stopped
|
||||
func (p *Provider) Stop() {
|
||||
close(p.stop)
|
||||
<-p.stopped
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package deals
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
@ -9,49 +10,48 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/cborrpc"
|
||||
datastore "github.com/ipfs/go-datastore"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
inet "github.com/libp2p/go-libp2p-core/network"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func (h *Handler) SetPrice(p types.BigInt, ttlsecs int64) error {
|
||||
h.askLk.Lock()
|
||||
defer h.askLk.Unlock()
|
||||
func (p *Provider) SetPrice(price types.BigInt, ttlsecs int64) error {
|
||||
p.askLk.Lock()
|
||||
defer p.askLk.Unlock()
|
||||
|
||||
var seqno uint64
|
||||
if h.ask != nil {
|
||||
seqno = h.ask.Ask.SeqNo + 1
|
||||
if p.ask != nil {
|
||||
seqno = p.ask.Ask.SeqNo + 1
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
ask := &types.StorageAsk{
|
||||
Price: p,
|
||||
Timestamp: now,
|
||||
Expiry: now + ttlsecs,
|
||||
Miner: h.actor,
|
||||
Price: price,
|
||||
Timestamp: uint64(now),
|
||||
Expiry: uint64(now + ttlsecs),
|
||||
Miner: p.actor,
|
||||
SeqNo: seqno,
|
||||
MinPieceSize: h.minPieceSize,
|
||||
MinPieceSize: p.minPieceSize,
|
||||
}
|
||||
|
||||
ssa, err := h.signAsk(ask)
|
||||
ssa, err := p.signAsk(ask)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return h.saveAsk(ssa)
|
||||
return p.saveAsk(ssa)
|
||||
}
|
||||
|
||||
func (h *Handler) getAsk(m address.Address) *types.SignedStorageAsk {
|
||||
h.askLk.Lock()
|
||||
defer h.askLk.Unlock()
|
||||
if m != h.actor {
|
||||
func (p *Provider) getAsk(m address.Address) *types.SignedStorageAsk {
|
||||
p.askLk.Lock()
|
||||
defer p.askLk.Unlock()
|
||||
if m != p.actor {
|
||||
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()
|
||||
var ar AskRequest
|
||||
if err := cborrpc.ReadCborRPC(s, &ar); err != nil {
|
||||
@ -59,7 +59,7 @@ func (h *Handler) HandleAskStream(s inet.Stream) {
|
||||
return
|
||||
}
|
||||
|
||||
resp := h.processAskRequest(&ar)
|
||||
resp := p.processAskRequest(&ar)
|
||||
|
||||
if err := cborrpc.WriteCborRPC(s, resp); err != nil {
|
||||
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{
|
||||
Ask: h.getAsk(ar.Miner),
|
||||
Ask: p.getAsk(ar.Miner),
|
||||
}
|
||||
}
|
||||
|
||||
var bestAskKey = datastore.NewKey("latest-ask")
|
||||
|
||||
func (h *Handler) tryLoadAsk() error {
|
||||
h.askLk.Lock()
|
||||
defer h.askLk.Unlock()
|
||||
func (p *Provider) tryLoadAsk() error {
|
||||
p.askLk.Lock()
|
||||
defer p.askLk.Unlock()
|
||||
|
||||
err := h.loadAsk()
|
||||
err := p.loadAsk()
|
||||
if err != nil {
|
||||
if xerrors.Is(err, datastore.ErrNotFound) {
|
||||
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
|
||||
}
|
||||
|
||||
func (h *Handler) loadAsk() error {
|
||||
askb, err := h.ds.Get(datastore.NewKey("latest-ask"))
|
||||
func (p *Provider) loadAsk() error {
|
||||
askb, err := p.ds.Get(datastore.NewKey("latest-ask"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load most recent ask from disk: %w", err)
|
||||
}
|
||||
|
||||
var ssa types.SignedStorageAsk
|
||||
if err := cbor.DecodeInto(askb, &ssa); err != nil {
|
||||
if err := cborrpc.ReadCborRPC(bytes.NewReader(askb), &ssa); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.ask = &ssa
|
||||
p.ask = &ssa
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) signAsk(a *types.StorageAsk) (*types.SignedStorageAsk, error) {
|
||||
b, err := cbor.DumpObject(a)
|
||||
func (p *Provider) signAsk(a *types.StorageAsk) (*types.SignedStorageAsk, error) {
|
||||
b, err := cborrpc.Dump(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
worker, err := h.getWorker(h.actor)
|
||||
worker, err := p.getWorker(p.actor)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@ -128,29 +128,29 @@ func (h *Handler) signAsk(a *types.StorageAsk) (*types.SignedStorageAsk, error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *Handler) saveAsk(a *types.SignedStorageAsk) error {
|
||||
b, err := cbor.DumpObject(a)
|
||||
func (p *Provider) saveAsk(a *types.SignedStorageAsk) error {
|
||||
b, err := cborrpc.Dump(a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := h.ds.Put(bestAskKey, b); err != nil {
|
||||
if err := p.ds.Put(bestAskKey, b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.ask = a
|
||||
p.ask = a
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) checkAskSignature(ask *types.SignedStorageAsk) error {
|
||||
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 {
|
||||
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 {
|
||||
return xerrors.Errorf("failed to re-serialize ask")
|
||||
}
|
309
chain/deals/provider_states.go
Normal file
309
chain/deals/provider_states.go
Normal file
@ -0,0 +1,309 @@
|
||||
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.BigDiv(types.BigMul(p.ask.Ask.Price, types.NewInt(deal.Proposal.PieceSize)), types.NewInt(1<<30))
|
||||
if deal.Proposal.StoragePricePerEpoch.LessThan(minPrice) {
|
||||
return nil, xerrors.Errorf("storage price per epoch less than asking price: %s < %s", deal.Proposal.StoragePricePerEpoch, 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.TotalStoragePrice()) {
|
||||
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)
|
||||
}
|
||||
|
||||
if err := p.secst.SealSector(ctx, deal.SectorID); err != nil {
|
||||
return nil, xerrors.Errorf("sealing sector failed: %w", 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/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
inet "github.com/libp2p/go-libp2p-core/network"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func (h *Handler) failDeal(id cid.Cid, cerr error) {
|
||||
if err := h.deals.End(id); err != nil {
|
||||
func (p *Provider) failDeal(id cid.Cid, cerr error) {
|
||||
if err := p.deals.End(id); err != nil {
|
||||
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)
|
||||
|
||||
err := h.sendSignedResponse(StorageDealResponse{
|
||||
err := p.sendSignedResponse(&Response{
|
||||
State: api.DealFailed,
|
||||
Message: cerr.Error(),
|
||||
Proposal: id,
|
||||
})
|
||||
|
||||
s, ok := h.conns[id]
|
||||
s, ok := p.conns[id]
|
||||
if ok {
|
||||
_ = s.Reset()
|
||||
delete(h.conns, id)
|
||||
delete(p.conns, id)
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
// (and signature, obviously)
|
||||
|
||||
if proposal.Proposal.MinerAddress != h.actor {
|
||||
log.Errorf("proposal with wrong MinerAddress: %s", proposal.Proposal.MinerAddress)
|
||||
return SignedStorageDealProposal{}, err
|
||||
if proposal.Provider != p.actor {
|
||||
log.Errorf("proposal with wrong ProviderAddress: %s", proposal.Provider)
|
||||
return proposal, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (h *Handler) sendSignedResponse(resp StorageDealResponse) error {
|
||||
s, ok := h.conns[resp.Proposal]
|
||||
func (p *Provider) sendSignedResponse(resp *Response) error {
|
||||
s, ok := p.conns[resp.Proposal]
|
||||
if !ok {
|
||||
return xerrors.New("couldn't send response: not connected")
|
||||
}
|
||||
|
||||
msg, err := cbor.DumpObject(&resp)
|
||||
msg, err := cborrpc.Dump(resp)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("serializing response: %w", err)
|
||||
}
|
||||
|
||||
worker, err := h.getWorker(h.actor)
|
||||
worker, err := p.getWorker(p.actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sig, err := h.full.WalletSign(context.TODO(), worker, msg)
|
||||
sig, err := p.full.WalletSign(context.TODO(), worker, msg)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to sign response message: %w", err)
|
||||
}
|
||||
|
||||
signedResponse := SignedStorageDealResponse{
|
||||
Response: resp,
|
||||
signedResponse := &SignedResponse{
|
||||
Response: *resp,
|
||||
Signature: sig,
|
||||
}
|
||||
|
||||
@ -93,18 +96,18 @@ func (h *Handler) sendSignedResponse(resp StorageDealResponse) error {
|
||||
if err != nil {
|
||||
// Assume client disconnected
|
||||
s.Close()
|
||||
delete(h.conns, resp.Proposal)
|
||||
delete(p.conns, resp.Proposal)
|
||||
}
|
||||
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{
|
||||
To: miner,
|
||||
From: miner,
|
||||
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 {
|
||||
return address.Undef, xerrors.Errorf("getting worker address: %w", err)
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
package deals
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/filecoin-project/lotus/lib/cborrpc"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/query"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"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)
|
||||
}
|
||||
|
||||
b, err := cbor.DumpObject(state)
|
||||
b, err := cborrpc.Dump(state)
|
||||
if err != nil {
|
||||
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) {
|
||||
return func(in []byte) ([]byte, error) {
|
||||
var deal MinerDeal
|
||||
err := cbor.DecodeInto(in, &deal)
|
||||
deal := new(MinerDeal)
|
||||
err := cborrpc.ReadCborRPC(bytes.NewReader(in), deal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := m(&deal); err != nil {
|
||||
if err := m(deal); err != nil {
|
||||
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) {
|
||||
return func(in []byte) ([]byte, error) {
|
||||
var deal ClientDeal
|
||||
err := cbor.DecodeInto(in, &deal)
|
||||
deal := new(ClientDeal)
|
||||
err := cborrpc.ReadCborRPC(bytes.NewReader(in), deal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := m(&deal); err != nil {
|
||||
if err := m(deal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cbor.DumpObject(deal)
|
||||
return cborrpc.Dump(deal)
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,7 +130,7 @@ func (st *ClientStateStore) ListClient() ([]ClientDeal, error) {
|
||||
}
|
||||
|
||||
var deal ClientDeal
|
||||
err := cbor.DecodeInto(res.Value, &deal)
|
||||
err := cborrpc.ReadCborRPC(bytes.NewReader(res.Value), &deal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -2,83 +2,37 @@ package deals
|
||||
|
||||
import (
|
||||
"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/address"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
func init() {
|
||||
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 DealProtocolID = "/fil/storage/mk/1.0.0"
|
||||
const AskProtocolID = "/fil/storage/ask/1.0.0"
|
||||
|
||||
type SerializationMode string
|
||||
|
||||
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 Proposal struct {
|
||||
DealProposal actors.StorageDealProposal
|
||||
}
|
||||
|
||||
type SignedStorageDealProposal struct {
|
||||
Proposal StorageDealProposal
|
||||
|
||||
Signature *types.Signature
|
||||
}
|
||||
|
||||
// response
|
||||
|
||||
type PieceInclusionProof struct {
|
||||
Position uint64
|
||||
ProofElements []byte
|
||||
}
|
||||
|
||||
type StorageDealResponse struct {
|
||||
type Response struct {
|
||||
State api.DealState
|
||||
|
||||
// DealRejected / DealAccepted / DealFailed / DealStaged
|
||||
// DealProposalRejected
|
||||
Message string
|
||||
Proposal cid.Cid
|
||||
|
||||
// DealSealing
|
||||
PieceInclusionProof PieceInclusionProof
|
||||
CommD []byte // TODO: not in spec
|
||||
// DealAccepted
|
||||
StorageDeal *actors.StorageDeal
|
||||
PublishMessage *cid.Cid
|
||||
|
||||
// DealComplete
|
||||
SectorCommitMessage *cid.Cid
|
||||
CommitMessage *cid.Cid
|
||||
}
|
||||
|
||||
type SignedStorageDealResponse struct {
|
||||
Response StorageDealResponse
|
||||
// TODO: Do we actually need this to be signed?
|
||||
type SignedResponse struct {
|
||||
Response Response
|
||||
|
||||
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,14 +206,14 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
|
||||
|
||||
st := pts.ParentState()
|
||||
|
||||
worker, err := stmgr.GetMinerWorker(ctx, cg.sm, st, m)
|
||||
worker, err := stmgr.GetMinerWorkerRaw(ctx, cg.sm, st, m)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, xerrors.Errorf("get miner worker: %w", err)
|
||||
}
|
||||
|
||||
vrfout, err := ComputeVRF(ctx, cg.w.Sign, worker, lastTicket.VRFProof)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, xerrors.Errorf("compute VRF: %w", err)
|
||||
}
|
||||
|
||||
tick := &types.Ticket{
|
||||
@ -252,7 +252,7 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad
|
||||
|
||||
msgs, err := cg.getRandomMessages()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, xerrors.Errorf("get random messages: %w", err)
|
||||
}
|
||||
|
||||
for len(blks) == 0 {
|
||||
@ -279,6 +279,12 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad
|
||||
}
|
||||
|
||||
fts := store.NewFullTipSet(blks)
|
||||
fmt.Println("Made a block: ", fts.TipSet().Cids())
|
||||
if len(fts.TipSet().Cids()) > 1 {
|
||||
for _, b := range blks {
|
||||
fmt.Printf("block %s: %#v\n", b.Cid(), b.Header)
|
||||
}
|
||||
}
|
||||
|
||||
return &MinedTipSet{
|
||||
TipSet: fts,
|
||||
@ -385,7 +391,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) {
|
||||
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) {
|
||||
@ -393,9 +399,9 @@ func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*ty
|
||||
}
|
||||
|
||||
func IsRoundWinner(ctx context.Context, ts *types.TipSet, ticks []*types.Ticket, miner address.Address, a MiningCheckAPI) (bool, types.ElectionProof, error) {
|
||||
r, err := a.ChainGetRandomness(ctx, ts, ticks, build.RandomnessLookback)
|
||||
r, err := a.ChainGetRandomness(ctx, ts, ticks, build.EcRandomnessLookback)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
return false, nil, xerrors.Errorf("chain get randomness: %w", err)
|
||||
}
|
||||
|
||||
mworker, err := a.StateMinerWorker(ctx, miner, ts)
|
||||
@ -413,7 +419,7 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, ticks []*types.Ticket,
|
||||
return false, nil, xerrors.Errorf("failed to check power: %w", err)
|
||||
}
|
||||
|
||||
return types.PowerCmp(vrfout, types.BigMul(pow.MinerPower, types.NewInt(build.BlocksPerEpoch)), pow.TotalPower), vrfout, nil
|
||||
return types.PowerCmp(vrfout, pow.MinerPower, pow.TotalPower), vrfout, nil
|
||||
}
|
||||
|
||||
type SignFunc func(context.Context, address.Address, []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))
|
||||
|
||||
worker, err := stmgr.GetMinerWorker(ctx, sm, st, miner)
|
||||
worker, err := stmgr.GetMinerWorkerRaw(ctx, sm, st, miner)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get miner worker: %w", err)
|
||||
}
|
||||
|
@ -5,6 +5,14 @@ import (
|
||||
"fmt"
|
||||
|
||||
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"
|
||||
actors "github.com/filecoin-project/lotus/chain/actors"
|
||||
"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/types"
|
||||
"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 {
|
||||
@ -56,7 +56,7 @@ func SetupInitActor(bs bstore.Blockstore, addrs []address.Address) (*types.Actor
|
||||
}
|
||||
|
||||
act := &types.Actor{
|
||||
Code: actors.InitActorCodeCid,
|
||||
Code: actors.InitCodeCid,
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
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{
|
||||
Code: actors.AccountActorCodeCid,
|
||||
Code: actors.AccountCodeCid,
|
||||
Balance: netAmt,
|
||||
Head: emptyobject,
|
||||
})
|
||||
@ -113,7 +122,7 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types
|
||||
}
|
||||
|
||||
err = state.SetActor(actors.BurntFundsAddress, &types.Actor{
|
||||
Code: actors.AccountActorCodeCid,
|
||||
Code: actors.AccountCodeCid,
|
||||
Balance: types.NewInt(0),
|
||||
Head: emptyobject,
|
||||
})
|
||||
@ -123,7 +132,7 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types
|
||||
|
||||
for a, v := range actmap {
|
||||
err = state.SetActor(a, &types.Actor{
|
||||
Code: actors.AccountActorCodeCid,
|
||||
Code: actors.AccountCodeCid,
|
||||
Balance: v,
|
||||
Head: emptyobject,
|
||||
})
|
||||
@ -135,7 +144,7 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
cst := hamt.CSTFromBstore(bs)
|
||||
nd := hamt.NewNode(cst)
|
||||
emptyhamt, err := cst.Put(context.TODO(), nd)
|
||||
@ -154,7 +163,41 @@ func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
}
|
||||
|
||||
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,
|
||||
Nonce: 0,
|
||||
Balance: types.NewInt(0),
|
||||
@ -196,13 +239,13 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
params := mustEnc(&actors.CreateStorageMinerParams{
|
||||
Owner: owner,
|
||||
Worker: worker,
|
||||
SectorSize: types.NewInt(build.SectorSize),
|
||||
SectorSize: build.SectorSizes[0],
|
||||
PeerID: pid,
|
||||
})
|
||||
|
||||
// TODO: hardcoding 7000000 here is a little fragile, it changes any
|
||||
// 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 {
|
||||
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)})
|
||||
|
||||
_, 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 {
|
||||
return cid.Undef, xerrors.Errorf("failed to update total storage: %w", err)
|
||||
}
|
||||
@ -329,11 +372,11 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B
|
||||
log.Infof("Empty Genesis root: %s", emptyroot)
|
||||
|
||||
genesisticket := &types.Ticket{
|
||||
VRFProof: []byte("vrf proof"),
|
||||
VRFProof: []byte("vrf proof0000000vrf proof0000000"),
|
||||
}
|
||||
|
||||
b := &types.BlockHeader{
|
||||
Miner: actors.InitActorAddress,
|
||||
Miner: actors.InitAddress,
|
||||
Tickets: []*types.Ticket{genesisticket},
|
||||
ElectionProof: []byte("the Genesis block"),
|
||||
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) {
|
||||
act, err := st.GetActor(actors.InitActorAddress)
|
||||
act, err := st.GetActor(actors.InitAddress)
|
||||
if err != nil {
|
||||
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) {
|
||||
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
|
||||
if err := st.Store.Get(context.TODO(), initact.Head, &ias); err != nil {
|
||||
return err
|
||||
|
@ -27,7 +27,7 @@ func BenchmarkStateTreeSet(b *testing.B) {
|
||||
err = st.SetActor(a, &types.Actor{
|
||||
Balance: types.NewInt(1258812523),
|
||||
Code: actors.StorageMinerCodeCid,
|
||||
Head: actors.AccountActorCodeCid,
|
||||
Head: actors.AccountCodeCid,
|
||||
Nonce: uint64(i),
|
||||
})
|
||||
if err != nil {
|
||||
@ -54,7 +54,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) {
|
||||
err = st.SetActor(a, &types.Actor{
|
||||
Balance: types.NewInt(1258812523),
|
||||
Code: actors.StorageMinerCodeCid,
|
||||
Head: actors.AccountActorCodeCid,
|
||||
Head: actors.AccountCodeCid,
|
||||
Nonce: uint64(i),
|
||||
})
|
||||
if err != nil {
|
||||
@ -80,7 +80,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) {
|
||||
err = st.SetActor(a, &types.Actor{
|
||||
Balance: types.NewInt(1258812523 + uint64(i)),
|
||||
Code: actors.StorageMinerCodeCid,
|
||||
Head: actors.AccountActorCodeCid,
|
||||
Head: actors.AccountCodeCid,
|
||||
Nonce: uint64(i),
|
||||
})
|
||||
if err != nil {
|
||||
@ -123,7 +123,7 @@ func TestSetCache(t *testing.T) {
|
||||
act := &types.Actor{
|
||||
Balance: types.NewInt(0),
|
||||
Code: actors.StorageMinerCodeCid,
|
||||
Head: actors.AccountActorCodeCid,
|
||||
Head: actors.AccountCodeCid,
|
||||
Nonce: 0,
|
||||
}
|
||||
|
||||
|
@ -462,3 +462,17 @@ func (sm *StateManager) ListAllActors(ctx context.Context, ts *types.TipSet) ([]
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package stmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/address"
|
||||
@ -9,6 +10,7 @@ import (
|
||||
|
||||
amt "github.com/filecoin-project/go-amt-ipld"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
@ -16,7 +18,7 @@ import (
|
||||
"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{
|
||||
To: maddr,
|
||||
From: maddr,
|
||||
@ -80,7 +82,7 @@ func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr add
|
||||
}
|
||||
ret, err := sm.Call(ctx, &types.Message{
|
||||
From: maddr,
|
||||
To: actors.StorageMarketAddress,
|
||||
To: actors.StoragePowerAddress,
|
||||
Method: actors.SPAMethods.PowerLookup,
|
||||
Params: enc,
|
||||
}, ts)
|
||||
@ -95,8 +97,8 @@ func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr add
|
||||
}
|
||||
|
||||
ret, err := sm.Call(ctx, &types.Message{
|
||||
From: actors.StorageMarketAddress,
|
||||
To: actors.StorageMarketAddress,
|
||||
From: actors.StoragePowerAddress,
|
||||
To: actors.StoragePowerAddress,
|
||||
Method: actors.SPAMethods.GetTotalStorage,
|
||||
}, ts)
|
||||
if err != nil {
|
||||
@ -118,7 +120,7 @@ func GetMinerPeerID(ctx context.Context, sm *StateManager, ts *types.TipSet, mad
|
||||
Method: actors.MAMethods.GetPeerID,
|
||||
}, ts)
|
||||
if err != nil {
|
||||
return "", xerrors.Errorf("callRaw failed: %w", err)
|
||||
return "", xerrors.Errorf("call failed: %w", err)
|
||||
}
|
||||
|
||||
if recp.ExitCode != 0 {
|
||||
@ -128,6 +130,23 @@ func GetMinerPeerID(ctx context.Context, sm *StateManager, ts *types.TipSet, mad
|
||||
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) {
|
||||
var mas actors.StorageMinerActorState
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
@ -158,6 +177,22 @@ func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet,
|
||||
return LoadSectorsFromSet(ctx, sm.ChainStore().Blockstore(), mas.Sectors)
|
||||
}
|
||||
|
||||
func GetMinerSectorSize(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (uint64, error) {
|
||||
var mas actors.StorageMinerActorState
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
cst := hamt.CSTFromBstore(sm.cs.Blockstore())
|
||||
var minfo actors.MinerInfo
|
||||
if err := cst.Get(ctx, mas.Info, &minfo); err != nil {
|
||||
return 0, xerrors.Errorf("failed to read miner info: %w", err)
|
||||
}
|
||||
|
||||
return minfo.SectorSize, nil
|
||||
}
|
||||
|
||||
func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid) ([]*api.SectorInfo, error) {
|
||||
blks := amt.WrapBlockstore(bs)
|
||||
a, err := amt.LoadAMT(blks, ssc)
|
||||
|
@ -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)
|
||||
|
||||
ret, err := cs.call(ctx, &types.Message{
|
||||
From: actors.StorageMarketAddress,
|
||||
To: actors.StorageMarketAddress,
|
||||
From: actors.StoragePowerAddress,
|
||||
To: actors.StoragePowerAddress,
|
||||
Method: actors.SPAMethods.GetTotalStorage,
|
||||
}, ts)
|
||||
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{
|
||||
To: actors.StorageMarketAddress,
|
||||
To: actors.StoragePowerAddress,
|
||||
From: maddr,
|
||||
Method: actors.SPAMethods.IsMiner,
|
||||
Params: enc,
|
||||
@ -482,9 +482,9 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) 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 {
|
||||
return xerrors.Errorf("GetMinerWorker failed: %w", err)
|
||||
return xerrors.Errorf("GetMinerWorkerRaw failed: %w", err)
|
||||
}
|
||||
|
||||
if err := h.CheckBlockSignature(ctx, waddr); err != nil {
|
||||
@ -495,7 +495,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
return xerrors.Errorf("validating block tickets failed: %w", err)
|
||||
}
|
||||
|
||||
rand, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs.Cids(), h.Tickets, build.RandomnessLookback)
|
||||
rand, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs.Cids(), h.Tickets, build.EcRandomnessLookback)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get randomness for verifying election proof: %w", err)
|
||||
}
|
||||
|
@ -16,10 +16,12 @@ type SignedStorageAsk struct {
|
||||
}
|
||||
|
||||
type StorageAsk struct {
|
||||
Price BigInt
|
||||
// Price per GiB / Epoch
|
||||
Price BigInt
|
||||
|
||||
MinPieceSize uint64
|
||||
Miner address.Address
|
||||
Timestamp int64
|
||||
Expiry int64
|
||||
Timestamp uint64
|
||||
Expiry uint64
|
||||
SeqNo uint64
|
||||
}
|
||||
|
@ -3,15 +3,16 @@ package types
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"math/big"
|
||||
|
||||
block "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/minio/sha256-simd"
|
||||
"github.com/multiformats/go-multihash"
|
||||
"go.opencensus.io/trace"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/address"
|
||||
)
|
||||
|
||||
@ -159,23 +160,30 @@ func CidArrsEqual(a, b []cid.Cid) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var blocksPerEpoch = NewInt(build.BlocksPerEpoch)
|
||||
|
||||
func PowerCmp(eproof ElectionProof, mpow, totpow BigInt) bool {
|
||||
|
||||
/*
|
||||
Need to check that
|
||||
h(vrfout) / 2^256 < minerPower / totalPower
|
||||
h(vrfout) / max(h) < e * minerPower / totalPower
|
||||
max(h) == 2^256-1
|
||||
which in terms of integer math means:
|
||||
h(vrfout) * totalPower < e * minerPower * (2^256-1)
|
||||
*/
|
||||
|
||||
h := sha256.Sum256(eproof)
|
||||
|
||||
// 2^256
|
||||
rden := BigInt{big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil)}
|
||||
lhs := BigFromBytes(h[:]).Int
|
||||
lhs = lhs.Mul(lhs, totpow.Int)
|
||||
|
||||
top := BigMul(rden, mpow)
|
||||
out := BigDiv(top, totpow)
|
||||
// rhs = minerPower * 2^256 - minerPower
|
||||
// rhs = minerPower << 256 - minerPower
|
||||
rhs := new(big.Int).Lsh(mpow.Int, 256)
|
||||
rhs = rhs.Mul(rhs, blocksPerEpoch.Int)
|
||||
rhs = rhs.Sub(rhs, mpow.Int)
|
||||
|
||||
hp := BigFromBytes(h[:])
|
||||
return hp.LessThan(out)
|
||||
return lhs.Cmp(rhs) == -1
|
||||
}
|
||||
|
||||
func (t *Ticket) Equals(ot *Ticket) bool {
|
||||
|
@ -27,7 +27,7 @@ func testBlockHeader(t testing.TB) *BlockHeader {
|
||||
ElectionProof: []byte("cats won the election"),
|
||||
Tickets: []*Ticket{
|
||||
&Ticket{
|
||||
VRFProof: []byte("vrf proof"),
|
||||
VRFProof: []byte("vrf proof0000000vrf proof0000000"),
|
||||
},
|
||||
},
|
||||
Parents: []cid.Cid{c, c},
|
||||
|
@ -1272,3 +1272,201 @@ func (t *BlockMsg) UnmarshalCBOR(r io.Reader) error {
|
||||
|
||||
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)
|
||||
inv.register(actors.InitActorCodeCid, actors.InitActor{}, actors.InitActorState{})
|
||||
inv.register(actors.StorageMarketActorCodeCid, actors.StoragePowerActor{}, actors.StoragePowerState{})
|
||||
inv.register(actors.InitCodeCid, actors.InitActor{}, actors.InitActorState{})
|
||||
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.MultisigActorCodeCid, actors.MultiSigActor{}, actors.MultiSigActorState{})
|
||||
inv.register(actors.PaymentChannelActorCodeCid, actors.PaymentChannelActor{}, actors.PaymentChannelActorState{})
|
||||
inv.register(actors.MultisigCodeCid, actors.MultiSigActor{}, actors.MultiSigActorState{})
|
||||
inv.register(actors.PaymentChannelCodeCid, actors.PaymentChannelActor{}, actors.PaymentChannelActorState{})
|
||||
|
||||
return inv
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ func NewBLSAccountActor(st *state.StateTree, addr address.Address) (*types.Actor
|
||||
}
|
||||
|
||||
nact := &types.Actor{
|
||||
Code: actors.AccountActorCodeCid,
|
||||
Code: actors.AccountCodeCid,
|
||||
Balance: types.NewInt(0),
|
||||
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) {
|
||||
nact := &types.Actor{
|
||||
Code: actors.AccountActorCodeCid,
|
||||
Code: actors.AccountCodeCid,
|
||||
Balance: types.NewInt(0),
|
||||
Head: EmptyObjectCid,
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ func (vmc *VMContext) ChargeGas(amount uint64) 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")
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
if act.Code != actors.AccountActorCodeCid {
|
||||
if act.Code != actors.AccountCodeCid {
|
||||
return address.Undef, aerrors.New(1, "address was not for an account actor")
|
||||
}
|
||||
|
||||
@ -488,6 +488,8 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
|
||||
return nil, xerrors.Errorf("getting block miner actor (%s) failed: %w", vm.blockMiner, err)
|
||||
}
|
||||
|
||||
// TODO: support multiple blocks in a tipset
|
||||
// TODO: actually wire this up (miner is undef for now)
|
||||
gasReward := types.BigMul(msg.GasPrice, gasUsed)
|
||||
if err := Transfer(gasHolder, miner, gasReward); err != nil {
|
||||
return nil, xerrors.Errorf("failed to give miner gas reward: %w", err)
|
||||
@ -630,6 +632,7 @@ func depositFunds(act *types.Actor, amt types.BigInt) {
|
||||
}
|
||||
|
||||
var miningRewardTotal = types.FromFil(build.MiningRewardTotal)
|
||||
var blocksPerEpoch = types.NewInt(build.BlocksPerEpoch)
|
||||
|
||||
// MiningReward returns correct mining reward
|
||||
// coffer is amount of FIL in NetworkAddress
|
||||
@ -637,5 +640,6 @@ func MiningReward(remainingReward types.BigInt) types.BigInt {
|
||||
ci := big.NewInt(0).Set(remainingReward.Int)
|
||||
res := ci.Mul(ci, build.InitialReward)
|
||||
res = res.Div(res, miningRewardTotal.Int)
|
||||
res = res.Div(res, blocksPerEpoch.Int)
|
||||
return types.BigInt{res}
|
||||
}
|
||||
|
@ -101,8 +101,7 @@ var clientDealCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: parse bigint
|
||||
price, err := strconv.ParseInt(cctx.Args().Get(2), 10, 32)
|
||||
price, err := types.ParseFIL(cctx.Args().Get(2))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -112,7 +111,7 @@ var clientDealCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
proposal, err := api.ClientStartDeal(ctx, data, miner, types.NewInt(uint64(price)), uint64(dur))
|
||||
proposal, err := api.ClientStartDeal(ctx, data, miner, types.BigInt(price), uint64(dur))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -164,7 +163,7 @@ var clientFindCmd = &cli.Command{
|
||||
fmt.Printf("ERR %s@%s: %s\n", offer.Miner, offer.MinerPeerID, offer.Err)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("RETRIEVAL %s@%s-%sfil-%db\n", offer.Miner, offer.MinerPeerID, offer.MinPrice, offer.Size)
|
||||
fmt.Printf("RETRIEVAL %s@%s-%sfil-%db\n", offer.Miner, offer.MinerPeerID, types.FIL(offer.MinPrice), offer.Size)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -308,19 +307,20 @@ var clientQueryAskCmd = &cli.Command{
|
||||
}
|
||||
|
||||
fmt.Printf("Ask: %s\n", maddr)
|
||||
fmt.Printf("Price per Byte: %s\n", ask.Ask.Price)
|
||||
fmt.Printf("Price per Byte: %s\n", types.FIL(ask.Ask.Price))
|
||||
|
||||
size := cctx.Int64("size")
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("Price per Block: %s\n", types.BigMul(ask.Ask.Price, types.NewInt(uint64(size))))
|
||||
perEpoch := types.BigDiv(types.BigMul(ask.Ask.Price, types.NewInt(uint64(size))), types.NewInt(1<<30))
|
||||
fmt.Printf("Price per Block: %s\n", types.FIL(perEpoch))
|
||||
|
||||
duration := cctx.Int64("duration")
|
||||
if duration == 0 {
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("Total Price: %s\n", types.BigMul(types.BigMul(ask.Ask.Price, types.NewInt(uint64(size))), types.NewInt(uint64(duration))))
|
||||
fmt.Printf("Total Price: %s\n", types.FIL(types.BigMul(perEpoch, types.NewInt(uint64(duration)))))
|
||||
|
||||
return nil
|
||||
},
|
||||
|
@ -53,7 +53,7 @@ var createMinerCmd = &cli.Command{
|
||||
createMinerArgs := actors.CreateStorageMinerParams{
|
||||
Worker: worker,
|
||||
Owner: owner,
|
||||
SectorSize: types.NewInt(ssize),
|
||||
SectorSize: ssize,
|
||||
PeerID: pid,
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ var createMinerCmd = &cli.Command{
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
To: actors.StorageMarketAddress,
|
||||
To: actors.StoragePowerAddress,
|
||||
From: addr,
|
||||
Method: actors.SPAMethods.CreateStorageMiner,
|
||||
Params: params,
|
||||
|
@ -78,7 +78,7 @@ var stateSectorsCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
sectors, err := api.StateMinerSectors(ctx, maddr)
|
||||
sectors, err := api.StateMinerSectors(ctx, maddr, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ var walletImport = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("imported key %s successfully!", addr)
|
||||
fmt.Printf("imported key %s successfully!\n", addr)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -5,14 +5,17 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
rice "github.com/GeertJohan/go.rice"
|
||||
logging "github.com/ipfs/go-log"
|
||||
peer "github.com/libp2p/go-libp2p-peer"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"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/address"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
@ -88,6 +91,22 @@ var runCmd = &cli.Command{
|
||||
ctx: ctx,
|
||||
api: nodeApi,
|
||||
from: from,
|
||||
limiter: NewLimiter(LimiterConfig{
|
||||
TotalRate: time.Second,
|
||||
TotalBurst: 20,
|
||||
IPRate: time.Minute,
|
||||
IPBurst: 5,
|
||||
WalletRate: 15 * time.Minute,
|
||||
WalletBurst: 1,
|
||||
}),
|
||||
colLimiter: NewLimiter(LimiterConfig{
|
||||
TotalRate: time.Second,
|
||||
TotalBurst: 20,
|
||||
IPRate: 10 * time.Minute,
|
||||
IPBurst: 1,
|
||||
WalletRate: 1 * time.Hour,
|
||||
WalletBurst: 1,
|
||||
}),
|
||||
}
|
||||
|
||||
http.Handle("/", http.FileServer(rice.MustFindBox("site").HTTPBox()))
|
||||
@ -110,9 +129,25 @@ type handler struct {
|
||||
api api.FullNode
|
||||
|
||||
from address.Address
|
||||
|
||||
limiter *Limiter
|
||||
colLimiter *Limiter
|
||||
}
|
||||
|
||||
func (h *handler) send(w http.ResponseWriter, r *http.Request) {
|
||||
// General limiter to allow throttling all messages that can make it into the mpool
|
||||
if !h.limiter.Allow() {
|
||||
http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
|
||||
// Limit based on IP
|
||||
limiter := h.limiter.GetIPLimiter(r.RemoteAddr)
|
||||
if !limiter.Allow() {
|
||||
http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
|
||||
to, err := address.NewFromString(r.FormValue("address"))
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
@ -120,6 +155,13 @@ func (h *handler) send(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Limit based on wallet address
|
||||
limiter = h.limiter.GetWalletLimiter(to.String())
|
||||
if !limiter.Allow() {
|
||||
http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
|
||||
smsg, err := h.api.MpoolPushMessage(h.ctx, &types.Message{
|
||||
Value: sendPerRequest,
|
||||
From: h.from,
|
||||
@ -138,6 +180,132 @@ func (h *handler) send(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(400)
|
||||
// todo
|
||||
// General limiter owner allow throttling all messages that can make it into the mpool
|
||||
if !h.colLimiter.Allow() {
|
||||
http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
|
||||
// Limit based on IP
|
||||
limiter := h.colLimiter.GetIPLimiter(r.RemoteAddr)
|
||||
if !limiter.Allow() {
|
||||
http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
|
||||
owner, err := address.NewFromString(r.FormValue("address"))
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if owner.Protocol() != address.BLS {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte("Miner address must use BLS"))
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("mkactor on %s", owner)
|
||||
|
||||
// Limit based on wallet address
|
||||
limiter = h.colLimiter.GetWalletLimiter(owner.String())
|
||||
if !limiter.Allow() {
|
||||
http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
collateral, err := h.api.StatePledgeCollateral(r.Context(), nil)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
smsg, err := h.api.MpoolPushMessage(h.ctx, &types.Message{
|
||||
Value: sendPerRequest,
|
||||
From: h.from,
|
||||
To: owner,
|
||||
|
||||
GasPrice: types.NewInt(0),
|
||||
GasLimit: types.NewInt(1000),
|
||||
})
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte("pushfunds: " + err.Error()))
|
||||
return
|
||||
}
|
||||
log.Infof("push funds to %s: %s", owner, smsg.Cid())
|
||||
|
||||
mw, err := h.api.StateWaitMsg(r.Context(), smsg.Cid())
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if mw.Receipt.ExitCode != 0 {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(xerrors.Errorf("create storage miner failed: exit code %d", mw.Receipt.ExitCode).Error()))
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("sendto %s ok", owner)
|
||||
|
||||
params, err := actors.SerializeParams(&actors.CreateStorageMinerParams{
|
||||
Owner: owner,
|
||||
Worker: owner,
|
||||
SectorSize: 1 << 30, // build.SectorSizes[0], // TODO: dropdown allowing selection (1GiB for now)
|
||||
PeerID: peer.ID("SETME"),
|
||||
})
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
createStorageMinerMsg := &types.Message{
|
||||
To: actors.StoragePowerAddress,
|
||||
From: h.from,
|
||||
Value: collateral,
|
||||
|
||||
Method: actors.SPAMethods.CreateStorageMiner,
|
||||
Params: params,
|
||||
|
||||
GasLimit: types.NewInt(10000000),
|
||||
GasPrice: types.NewInt(0),
|
||||
}
|
||||
|
||||
signed, err := h.api.MpoolPushMessage(r.Context(), createStorageMinerMsg)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("smc %s", owner)
|
||||
|
||||
mw, err = h.api.StateWaitMsg(r.Context(), signed.Cid())
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if mw.Receipt.ExitCode != 0 {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(xerrors.Errorf("create storage miner failed: exit code %d", mw.Receipt.ExitCode).Error()))
|
||||
return
|
||||
}
|
||||
|
||||
addr, err := address.NewFromBytes(mw.Receipt.Return)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(200)
|
||||
fmt.Fprintf(w, "New storage miners address is: %s\n", addr)
|
||||
fmt.Fprintf(w, "Run lotus-storage-miner init --actor=%s --owner=%s", addr, owner)
|
||||
}
|
||||
|
94
cmd/lotus-fountain/rate_limiter.go
Normal file
94
cmd/lotus-fountain/rate_limiter.go
Normal file
@ -0,0 +1,94 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
type Limiter struct {
|
||||
control *rate.Limiter
|
||||
|
||||
ips map[string]*rate.Limiter
|
||||
wallets map[string]*rate.Limiter
|
||||
mu *sync.RWMutex
|
||||
|
||||
config LimiterConfig
|
||||
}
|
||||
|
||||
type LimiterConfig struct {
|
||||
TotalRate time.Duration
|
||||
TotalBurst int
|
||||
|
||||
IPRate time.Duration
|
||||
IPBurst int
|
||||
|
||||
WalletRate time.Duration
|
||||
WalletBurst int
|
||||
}
|
||||
|
||||
func NewLimiter(c LimiterConfig) *Limiter {
|
||||
return &Limiter{
|
||||
control: rate.NewLimiter(rate.Every(c.TotalRate), c.TotalBurst),
|
||||
mu: &sync.RWMutex{},
|
||||
ips: make(map[string]*rate.Limiter),
|
||||
wallets: make(map[string]*rate.Limiter),
|
||||
|
||||
config: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Limiter) Allow() bool {
|
||||
return i.control.Allow()
|
||||
}
|
||||
|
||||
func (i *Limiter) AddIPLimiter(ip string) *rate.Limiter {
|
||||
i.mu.Lock()
|
||||
defer i.mu.Unlock()
|
||||
|
||||
limiter := rate.NewLimiter(rate.Every(i.config.IPRate), i.config.IPBurst)
|
||||
|
||||
i.ips[ip] = limiter
|
||||
|
||||
return limiter
|
||||
}
|
||||
|
||||
func (i *Limiter) GetIPLimiter(ip string) *rate.Limiter {
|
||||
i.mu.Lock()
|
||||
limiter, exists := i.ips[ip]
|
||||
|
||||
if !exists {
|
||||
i.mu.Unlock()
|
||||
return i.AddIPLimiter(ip)
|
||||
}
|
||||
|
||||
i.mu.Unlock()
|
||||
|
||||
return limiter
|
||||
}
|
||||
|
||||
func (i *Limiter) AddWalletLimiter(addr string) *rate.Limiter {
|
||||
i.mu.Lock()
|
||||
defer i.mu.Unlock()
|
||||
|
||||
limiter := rate.NewLimiter(rate.Every(i.config.WalletRate), i.config.WalletBurst)
|
||||
|
||||
i.wallets[addr] = limiter
|
||||
|
||||
return limiter
|
||||
}
|
||||
|
||||
func (i *Limiter) GetWalletLimiter(wallet string) *rate.Limiter {
|
||||
i.mu.Lock()
|
||||
limiter, exists := i.wallets[wallet]
|
||||
|
||||
if !exists {
|
||||
i.mu.Unlock()
|
||||
return i.AddWalletLimiter(wallet)
|
||||
}
|
||||
|
||||
i.mu.Unlock()
|
||||
|
||||
return limiter
|
||||
}
|
38
cmd/lotus-fountain/rate_limiter_test.go
Normal file
38
cmd/lotus-fountain/rate_limiter_test.go
Normal file
@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRateLimit(t *testing.T) {
|
||||
limiter := NewLimiter(LimiterConfig{
|
||||
TotalRate: time.Second,
|
||||
TotalBurst: 20,
|
||||
IPRate: time.Second,
|
||||
IPBurst: 1,
|
||||
WalletRate: time.Second,
|
||||
WalletBurst: 1,
|
||||
})
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
assert.True(t, limiter.Allow())
|
||||
}
|
||||
|
||||
assert.False(t, limiter.Allow())
|
||||
|
||||
time.Sleep(time.Second)
|
||||
assert.True(t, limiter.Allow())
|
||||
|
||||
assert.True(t, limiter.GetIPLimiter("127.0.0.1").Allow())
|
||||
assert.False(t, limiter.GetIPLimiter("127.0.0.1").Allow())
|
||||
time.Sleep(time.Second)
|
||||
assert.True(t, limiter.GetIPLimiter("127.0.0.1").Allow())
|
||||
|
||||
assert.True(t, limiter.GetWalletLimiter("abc123").Allow())
|
||||
assert.False(t, limiter.GetWalletLimiter("abc123").Allow())
|
||||
time.Sleep(time.Second)
|
||||
assert.True(t, limiter.GetWalletLimiter("abc123").Allow())
|
||||
}
|
29
cmd/lotus-fountain/site/funds.html
Normal file
29
cmd/lotus-fountain/site/funds.html
Normal file
@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Sending Funds - Lotus Fountain</title>
|
||||
<link rel="stylesheet" type="text/css" href="main.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="Index">
|
||||
<div class="Index-nodes">
|
||||
<div class="Index-node">
|
||||
[SENDING FUNDS]
|
||||
</div>
|
||||
<div class="Index-node">
|
||||
<form action='/send' method='get'>
|
||||
<span>Enter destination address:</span>
|
||||
<input type='text' name='address' style="width: 300px">
|
||||
<button type='submit'>Send Funds</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="Index-footer">
|
||||
<div>
|
||||
<a href="index.html">[Back]</a>
|
||||
<span style="float: right">Not dispensing real Filecoin tokens</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -2,19 +2,26 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Lotus Fountain</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'monospace';
|
||||
background: #1f1f1f;
|
||||
color: #f0f0f0;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="main.css">
|
||||
</head>
|
||||
<body>
|
||||
<form action='/send' method='get'>
|
||||
<span>Enter destination address:</span>
|
||||
<input type='text' name='address' style="width: 300px">
|
||||
<button type='submit'>Send</button>
|
||||
</form>
|
||||
<div class="Index">
|
||||
<div class="Index-nodes">
|
||||
<div class="Index-node">
|
||||
[LOTUS DEVNET FAUCET]
|
||||
</div>
|
||||
<div class="Index-node">
|
||||
<a href="funds.html">[Send Funds]</a>
|
||||
</div>
|
||||
<div class="Index-node">
|
||||
<a href="miner.html">[Create Miner]</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="Index-footer">
|
||||
<div>
|
||||
<span style="float: right">Not dispensing real Filecoin tokens</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
56
cmd/lotus-fountain/site/main.css
Normal file
56
cmd/lotus-fountain/site/main.css
Normal file
@ -0,0 +1,56 @@
|
||||
body {
|
||||
font-family: 'monospace';
|
||||
background: #1f1f1f;
|
||||
color: #f0f0f0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.Index {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: #1a1a1a;
|
||||
color: #f0f0f0;
|
||||
font-family: monospace;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: auto 40vw auto;
|
||||
grid-template-rows: auto auto auto 3em;
|
||||
grid-template-areas:
|
||||
". . ."
|
||||
". main ."
|
||||
". . ."
|
||||
"footer footer footer";
|
||||
}
|
||||
.Index-footer {
|
||||
background: #2a2a2a;
|
||||
grid-area: footer;
|
||||
}
|
||||
|
||||
.Index-footer > div {
|
||||
padding-left: 0.7em;
|
||||
padding-top: 0.7em;
|
||||
}
|
||||
|
||||
.Index-nodes {
|
||||
grid-area: main;
|
||||
background: #2a2a2a;
|
||||
}
|
||||
|
||||
.Index-node {
|
||||
margin: 5px;
|
||||
padding: 15px;
|
||||
background: #1f1f1f;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: #50f020;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #50f020;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #30a00a;
|
||||
}
|
43
cmd/lotus-fountain/site/miner.html
Normal file
43
cmd/lotus-fountain/site/miner.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Creating Storage Miner - Lotus Fountain</title>
|
||||
<link rel="stylesheet" type="text/css" href="main.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="Index">
|
||||
<div class="Index-nodes">
|
||||
<div class="Index-node">
|
||||
[CREATING STORAGE MINER]
|
||||
</div>
|
||||
<div class="Index-node" id="formnd">
|
||||
<form id="f" action='/mkminer' method='get'>
|
||||
<span>Enter destination address:</span>
|
||||
<input type='text' name='address' style="width: 300px">
|
||||
<button type='submit'>Create Miner</button>
|
||||
</form>
|
||||
</div>
|
||||
<div id="plswait" style="display: none" class="Index-node">
|
||||
<b>Waiting for transaction on chain..</b>
|
||||
</div>
|
||||
<div class="Index-node">
|
||||
<span>When creating storage miner, DO NOT REFRESH THE PAGE, wait for it to load. This can take more than 5min.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="Index-footer">
|
||||
<div>
|
||||
<a href="index.html">[Back]</a>
|
||||
<span style="float: right">Not dispensing real Filecoin tokens</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
let f = document.getElementById('f')
|
||||
f.onsubmit = ev => {
|
||||
document.getElementById('plswait').style.display = 'block'
|
||||
document.getElementById('formnd').style.display = 'none'
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -49,6 +49,11 @@ var initCmd = &cli.Command{
|
||||
Aliases: []string{"o"},
|
||||
Usage: "owner key to use",
|
||||
},
|
||||
&cli.Uint64Flag{
|
||||
Name: "sector-size",
|
||||
Usage: "specify sector size to use",
|
||||
Value: build.SectorSizes[0],
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
log.Info("Initializing lotus storage miner")
|
||||
@ -276,6 +281,8 @@ func createStorageMiner(ctx context.Context, api api.FullNode, peerid peer.ID, c
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
ssize := cctx.Uint64("sector-size")
|
||||
|
||||
worker := owner
|
||||
if cctx.String("worker") != "" {
|
||||
worker, err = address.NewFromString(cctx.String("worker"))
|
||||
@ -295,7 +302,7 @@ func createStorageMiner(ctx context.Context, api api.FullNode, peerid peer.ID, c
|
||||
params, err := actors.SerializeParams(&actors.CreateStorageMinerParams{
|
||||
Owner: owner,
|
||||
Worker: worker,
|
||||
SectorSize: types.NewInt(build.SectorSize),
|
||||
SectorSize: ssize,
|
||||
PeerID: peerid,
|
||||
})
|
||||
if err != nil {
|
||||
@ -303,7 +310,7 @@ func createStorageMiner(ctx context.Context, api api.FullNode, peerid peer.ID, c
|
||||
}
|
||||
|
||||
createStorageMinerMsg := &types.Message{
|
||||
To: actors.StorageMarketAddress,
|
||||
To: actors.StoragePowerAddress,
|
||||
From: owner,
|
||||
Value: collateral,
|
||||
|
||||
|
@ -36,7 +36,6 @@ var sectorsCmd = &cli.Command{
|
||||
Subcommands: []*cli.Command{
|
||||
sectorsStatusCmd,
|
||||
sectorsStagedListCmd,
|
||||
sectorsStagedSealCmd,
|
||||
sectorsRefsCmd,
|
||||
},
|
||||
}
|
||||
@ -71,7 +70,8 @@ var sectorsStatusCmd = &cli.Command{
|
||||
fmt.Printf("SealErrorMsg:\t%q\n", status.SealErrorMsg)
|
||||
fmt.Printf("CommD:\t\t%x\n", status.CommD)
|
||||
fmt.Printf("CommR:\t\t%x\n", status.CommR)
|
||||
fmt.Printf("CommR*:\t\t%x\n", status.CommRStar)
|
||||
fmt.Printf("Ticket:\t\t%x\n", status.Ticket.TicketBytes)
|
||||
fmt.Printf("TicketH:\t\t%d\n", status.Ticket.BlockHeight)
|
||||
fmt.Printf("Proof:\t\t%x\n", status.Proof)
|
||||
fmt.Printf("Pieces:\t\t%v\n", status.Pieces)
|
||||
return nil
|
||||
@ -101,21 +101,6 @@ var sectorsStagedListCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var sectorsStagedSealCmd = &cli.Command{
|
||||
Name: "seal-staged", // TODO: nest this under a 'staged' subcommand? idk
|
||||
Usage: "Seal staged sectors",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
return nodeApi.SectorsStagedSeal(ctx)
|
||||
},
|
||||
}
|
||||
|
||||
var sectorsRefsCmd = &cli.Command{
|
||||
Name: "refs",
|
||||
Usage: "List References to sectors",
|
||||
|
@ -1,9 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/ipfs/go-car"
|
||||
"github.com/ipfs/go-datastore"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@ -14,11 +19,26 @@ import (
|
||||
pnet "github.com/libp2p/go-libp2p-pnet"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
|
||||
"github.com/filecoin-project/lotus/lib/addrutil"
|
||||
"github.com/filecoin-project/lotus/node/modules/lp2p"
|
||||
)
|
||||
|
||||
const topic = "/fil/headnotifs/bafy2bzacea77zxnepp7wuqqgpj7xcw2ywwmmcmtrbjghhv4g2dildogpv6roi"
|
||||
var topic = "/fil/headnotifs/"
|
||||
|
||||
func init() {
|
||||
genBytes := build.MaybeGenesis()
|
||||
bs := blockstore.NewBlockstore(datastore.NewMapDatastore())
|
||||
|
||||
c, err := car.LoadCar(bs, bytes.NewReader(genBytes))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if len(c.Roots) != 1 {
|
||||
panic("expected genesis file to have one root")
|
||||
}
|
||||
|
||||
fmt.Printf("Genesis CID: %s\n", c.Roots[0])
|
||||
topic = topic + c.Roots[0].String()
|
||||
}
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
WriteBufferSize: 1024,
|
||||
@ -48,9 +68,7 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pi, err := addrutil.ParseAddresses(ctx, []string{
|
||||
"/ip4/147.75.80.29/tcp/1347/p2p/12D3KooWGU8C1mFsEtz4bXmHUH3kQTnQnxVy8cigwGV94qCpYJw7",
|
||||
})
|
||||
pi, err := build.BuiltinBootstrap()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
2
extern/go-sectorbuilder
vendored
2
extern/go-sectorbuilder
vendored
@ -1 +1 @@
|
||||
Subproject commit 32e85ba52d9ccf3fc5715bcf53265b042020ee82
|
||||
Subproject commit 692725ff21919ce9c9df9ea87621b0c1e6a9746c
|
37
gen/main.go
37
gen/main.go
@ -4,9 +4,11 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
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() {
|
||||
@ -22,6 +24,8 @@ func main() {
|
||||
types.Actor{},
|
||||
types.MessageReceipt{},
|
||||
types.BlockMsg{},
|
||||
types.SignedStorageAsk{},
|
||||
types.StorageAsk{},
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
@ -46,11 +50,9 @@ func main() {
|
||||
actors.AccountActorState{},
|
||||
actors.StorageMinerActorState{},
|
||||
actors.StorageMinerConstructorParams{},
|
||||
actors.CommitSectorParams{},
|
||||
actors.OnChainSealVerifyInfo{},
|
||||
actors.MinerInfo{},
|
||||
actors.SubmitPoStParams{},
|
||||
actors.PieceInclVoucherData{},
|
||||
actors.InclusionProof{},
|
||||
actors.PaymentVerifyParams{},
|
||||
actors.UpdatePeerIDParams{},
|
||||
actors.MultiSigActorState{},
|
||||
@ -75,6 +77,31 @@ func main() {
|
||||
actors.ArbitrateConsensusFaultParams{},
|
||||
actors.PledgeCollateralParams{},
|
||||
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 {
|
||||
fmt.Println(err)
|
||||
|
3
go.mod
3
go.mod
@ -61,6 +61,7 @@ require (
|
||||
github.com/mattn/go-runewidth v0.0.4 // indirect
|
||||
github.com/miekg/dns v1.1.16 // indirect
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1
|
||||
github.com/minio/sha256-simd v0.1.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/multiformats/go-base32 v0.0.3
|
||||
github.com/multiformats/go-multiaddr v0.0.4
|
||||
@ -79,10 +80,12 @@ require (
|
||||
go.uber.org/dig v1.7.0 // indirect
|
||||
go.uber.org/fx v1.9.0
|
||||
go.uber.org/goleak v0.10.0 // indirect
|
||||
go.uber.org/multierr v1.1.0
|
||||
go.uber.org/zap v1.10.0
|
||||
go4.org v0.0.0-20190313082347-94abd6928b1d // indirect
|
||||
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 // indirect
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd // indirect
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7
|
||||
google.golang.org/api v0.9.0 // indirect
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28
|
||||
|
132
go.sum
132
go.sum
@ -13,8 +13,10 @@ github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo
|
||||
github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ=
|
||||
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
||||
github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=
|
||||
github.com/OpenPeeDeeP/depguard v1.0.0/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo=
|
||||
@ -28,6 +30,8 @@ github.com/apache/thrift v0.12.0 h1:pODnxUFNcjP9UTLZGTdeh+j16A8lJbRvD3rOtrk/7bs=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
|
||||
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
||||
github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
||||
@ -71,6 +75,7 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/filecoin-project/go-amt-ipld v0.0.0-20190919045431-3650716fff16 h1:NzojcJU1VbS6zdLG13JMYis/cQy/MrN3rxmZRq56jKA=
|
||||
@ -83,16 +88,35 @@ github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 h1:EzDjxMg43q1tA2c0MV3tNbaontnHLplHyFF
|
||||
github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1/go.mod h1:0eHX/BVySxPc6SE2mZRoppGq7qcEagxdmQnA3dzork8=
|
||||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI=
|
||||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
||||
github.com/go-critic/go-critic v0.3.5-0.20190526074819-1df300866540/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
|
||||
github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
|
||||
github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
|
||||
github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
|
||||
github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg=
|
||||
github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
|
||||
github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU=
|
||||
github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk=
|
||||
github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI=
|
||||
github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks=
|
||||
github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc=
|
||||
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
|
||||
github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.0.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
@ -102,11 +126,29 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
|
||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
|
||||
github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0=
|
||||
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8=
|
||||
github.com/golangci/go-tools v0.0.0-20190318055746-e32c54105b7c/go.mod h1:unzUULGw35sjyOYjUt0jMTXqHlZPpPc6e+xfO4cd6mM=
|
||||
github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o=
|
||||
github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU=
|
||||
github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
|
||||
github.com/golangci/golangci-lint v1.18.0/go.mod h1:kaqo8l0OZKYPtjNmG4z4HrWLgcYNIJ9B9q3LWri9uLg=
|
||||
github.com/golangci/gosec v0.0.0-20190211064107-66fb7fc33547/go.mod h1:0qUabqiIQgfmlAmulqxyiGkkyF6/tOGSnY2cnPVwrzU=
|
||||
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU=
|
||||
github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
|
||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
|
||||
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
|
||||
github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI=
|
||||
github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4=
|
||||
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
@ -121,6 +163,7 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
|
||||
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
|
||||
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
@ -131,6 +174,7 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
|
||||
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
@ -247,6 +291,8 @@ github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M
|
||||
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
@ -254,8 +300,13 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b h1:wxtKgYHEncAU00muMD06dzLiahtGM1eouRNOzVV7tdQ=
|
||||
github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
|
||||
@ -382,8 +433,10 @@ github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw
|
||||
github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
|
||||
github.com/libp2p/go-yamux v1.2.3 h1:xX8A36vpXb59frIzWFdEgptLMsOANMFq2K7fPRlunYI=
|
||||
github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/lucas-clemente/quic-go v0.11.2 h1:Mop0ac3zALaBR3wGs6j8OYe/tcFvFsxTUFMkE/7yUOI=
|
||||
github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw=
|
||||
github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA=
|
||||
@ -392,6 +445,7 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
@ -399,6 +453,7 @@ github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
@ -410,9 +465,17 @@ github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+
|
||||
github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
|
||||
github.com/minio/sha256-simd v0.1.0 h1:U41/2erhAKcmSI14xh/ZTUdBPOzDOIfS93ibzUSl8KM=
|
||||
github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mozilla/tls-observatory v0.0.0-20180409132520-8791a200eb40/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
|
||||
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
||||
github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
||||
github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78=
|
||||
@ -440,21 +503,30 @@ github.com/multiformats/go-multihash v0.0.7/go.mod h1:XuKXPp8VHcTygube3OWZC+aZrA
|
||||
github.com/multiformats/go-multistream v0.1.0 h1:UpO6jrsjqs46mqAK3n6wKRYFhugss9ArzbyUzU+4wkQ=
|
||||
github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20160627004424-a22cb81b2ecd/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20171102151520-eafdab6b0663/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
|
||||
github.com/neelance/parallel v0.0.0-20160708114440-4de9ce63d14c/go.mod h1:eTBvSIlRgLo+CNFFQRQTwUGTZOEdvXIKeZS/xG+D2yU=
|
||||
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg=
|
||||
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg=
|
||||
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.9.0 h1:SZjF721BByVj8QH636/8S2DnX4n0Re3SteMmw3N+tzc=
|
||||
github.com/onsi/ginkgo v1.9.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.6.0 h1:8XTW0fcJZEq9q+Upcyws4JSGua2MFysCL5xkaSgHc+M=
|
||||
github.com/onsi/gomega v1.6.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@ -469,16 +541,32 @@ github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a h1:hjZfReYVLbqFkAtr
|
||||
github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM=
|
||||
github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/slimsag/godocmd v0.0.0-20161025000126-a1005ad29fe3/go.mod h1:AIBPxLCkKUFc2ZkjCXzs/Kk9OUhQLw/Zicdd0Rhqz2U=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
||||
github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w=
|
||||
@ -488,17 +576,27 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:s
|
||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=
|
||||
github.com/sourcegraph/ctxvfs v0.0.0-20180418081416-2b65f1b1ea81/go.mod h1:xIvvI5FiHLxhv8prbzVpaMHaaGPFPFQSuTcxC91ryOo=
|
||||
github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE=
|
||||
github.com/sourcegraph/go-langserver v2.0.0+incompatible/go.mod h1:bBMjfpzEHd6ijPRoQ7f+knFfw+e8R+W158/MsqAy77c=
|
||||
github.com/sourcegraph/jsonrpc2 v0.0.0-20190106185902-35a74f039c6a/go.mod h1:eESpbCslcLDs8j2D7IEdGVgul7xuk9odqDTaor30IUU=
|
||||
github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0=
|
||||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
|
||||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@ -508,12 +606,19 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
|
||||
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
|
||||
github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
|
||||
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
|
||||
github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830 h1:8kxMKmKzXXL4Ru1nyhvdms/JjWt+3YLpvRb/bAjO/y0=
|
||||
github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
|
||||
@ -571,11 +676,13 @@ golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnf
|
||||
golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 h1:Gv7RPwsi3eZ2Fgewe3CBsuOebPwO27PoXzRpJPsvSSM=
|
||||
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@ -585,9 +692,11 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -601,6 +710,7 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@ -613,6 +723,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20171026204733-164713f0dfce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -625,6 +736,7 @@ golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -632,26 +744,38 @@ golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20170915090833-1cbadb444a80/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20170915040203-e531a2a1c15f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190121143147-24cd39ecf745/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190813142322-97f12d73768f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190909030654-5b82db07426d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -672,20 +796,24 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
||||
gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8=
|
||||
gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/urfave/cli.v2 v2.0.0-20180128182452-d3ae77c26ac8 h1:Ggy3mWN4l3PUFPfSG0YB3n5fVYggzysUmiUQ89SnX6Y=
|
||||
gopkg.in/urfave/cli.v2 v2.0.0-20180128182452-d3ae77c26ac8/go.mod h1:cKXr3E0k4aosgycml1b5z33BVV6hai1Kh7uDgFOkbcs=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
@ -697,3 +825,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54=
|
||||
launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM=
|
||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
|
||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
|
||||
mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34/go.mod h1:H6SUd1XjIs+qQCyskXg5OFSrilMRUkD8ePJpHKDPaeY=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
|
@ -1,10 +1,13 @@
|
||||
package cborrpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"math"
|
||||
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
ipld "github.com/ipfs/go-ipld-format"
|
||||
logging "github.com/ipfs/go-log"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
)
|
||||
@ -43,3 +46,23 @@ func ReadCborRPC(r io.Reader, out interface{}) error {
|
||||
}
|
||||
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 {
|
||||
err := callResult[handler.errOut].Interface()
|
||||
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{
|
||||
Code: 1,
|
||||
Message: err.(error).Error(),
|
||||
|
@ -1,7 +1,6 @@
|
||||
package sectorbuilder
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
@ -25,6 +24,10 @@ type SortedSectorInfo = sectorbuilder.SortedSectorInfo
|
||||
|
||||
type SectorInfo = sectorbuilder.SectorInfo
|
||||
|
||||
type SealTicket = sectorbuilder.SealTicket
|
||||
|
||||
type SealedSectorMetadata = sectorbuilder.SealedSectorMetadata
|
||||
|
||||
const CommLen = sectorbuilder.CommitmentBytesLen
|
||||
|
||||
type SectorBuilder struct {
|
||||
@ -42,7 +45,7 @@ type SectorBuilderConfig struct {
|
||||
func New(cfg *SectorBuilderConfig) (*SectorBuilder, error) {
|
||||
proverId := addressToProverID(cfg.Miner)
|
||||
|
||||
sbp, err := sectorbuilder.InitSectorBuilder(cfg.SectorSize, 2, 1, 1, cfg.MetadataDir, proverId, cfg.SealedDir, cfg.StagedDir, 16)
|
||||
sbp, err := sectorbuilder.InitSectorBuilder(cfg.SectorSize, 2, 1, 0, cfg.MetadataDir, proverId, cfg.SealedDir, cfg.StagedDir, 16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -52,18 +55,12 @@ func New(cfg *SectorBuilderConfig) (*SectorBuilder, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func addressToProverID(a address.Address) [31]byte {
|
||||
var proverId [31]byte
|
||||
func addressToProverID(a address.Address) [32]byte {
|
||||
var proverId [32]byte
|
||||
copy(proverId[:], a.Payload())
|
||||
return proverId
|
||||
}
|
||||
|
||||
func sectorIDtoBytes(sid uint64) [31]byte {
|
||||
var out [31]byte
|
||||
binary.LittleEndian.PutUint64(out[:], sid)
|
||||
return out
|
||||
}
|
||||
|
||||
func (sb *SectorBuilder) Destroy() {
|
||||
sectorbuilder.DestroySectorBuilder(sb.handle)
|
||||
}
|
||||
@ -87,8 +84,8 @@ func (sb *SectorBuilder) ReadPieceFromSealedSector(pieceKey string) ([]byte, err
|
||||
return sectorbuilder.ReadPieceFromSealedSector(sb.handle, pieceKey)
|
||||
}
|
||||
|
||||
func (sb *SectorBuilder) SealAllStagedSectors() error {
|
||||
return sectorbuilder.SealAllStagedSectors(sb.handle)
|
||||
func (sb *SectorBuilder) SealSector(sectorID uint64, ticket SealTicket) (SealedSectorMetadata, error) {
|
||||
return sectorbuilder.SealSector(sb.handle, sectorID, ticket)
|
||||
}
|
||||
|
||||
func (sb *SectorBuilder) SealStatus(sector uint64) (SectorSealingStatus, error) {
|
||||
@ -121,14 +118,14 @@ func (sb *SectorBuilder) GeneratePoSt(sectorInfo SortedSectorInfo, challengeSeed
|
||||
|
||||
var UserBytesForSectorSize = sectorbuilder.GetMaxUserBytesPerStagedSector
|
||||
|
||||
func VerifySeal(sectorSize uint64, commR, commD, commRStar []byte, proverID address.Address, sectorID uint64, proof []byte) (bool, error) {
|
||||
var commRa, commDa, commRStara [32]byte
|
||||
func VerifySeal(sectorSize uint64, commR, commD []byte, proverID address.Address, ticket []byte, sectorID uint64, proof []byte) (bool, error) {
|
||||
var commRa, commDa, ticketa [32]byte
|
||||
copy(commRa[:], commR)
|
||||
copy(commDa[:], commD)
|
||||
copy(commRStara[:], commRStar)
|
||||
copy(ticketa[:], ticket)
|
||||
proverIDa := addressToProverID(proverID)
|
||||
|
||||
return sectorbuilder.VerifySeal(sectorSize, commRa, commDa, commRStara, proverIDa, sectorID, proof)
|
||||
return sectorbuilder.VerifySeal(sectorSize, commRa, commDa, proverIDa, ticketa, sectorID, proof)
|
||||
}
|
||||
|
||||
func VerifyPieceInclusionProof(sectorSize uint64, pieceSize uint64, commP []byte, commD []byte, proof []byte) (bool, error) {
|
||||
|
@ -1,50 +1,81 @@
|
||||
package sectorbuilder_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-datastore"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/address"
|
||||
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
||||
"github.com/filecoin-project/lotus/storage/sector"
|
||||
)
|
||||
|
||||
const sectorSize = 1024
|
||||
|
||||
func TestSealAndVerify(t *testing.T) {
|
||||
t.Skip("this is slow")
|
||||
build.SectorSizes = []uint64{sectorSize}
|
||||
|
||||
if err := build.GetParams(true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir("", "sbtest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString("t1tct3nfaw2q543xtybxcyw4deyxmfwkjk43u4t5y")
|
||||
addr, err := address.NewFromString("t3vfxagwiegrywptkbmyohqqbfzd7xzbryjydmxso4hfhgsnv6apddyihltsbiikjf3lm7x2myiaxhuc77capq")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
metadata := filepath.Join(dir, "meta")
|
||||
sealed := filepath.Join(dir, "sealed")
|
||||
staging := filepath.Join(dir, "staging")
|
||||
|
||||
sb, err := sectorbuilder.New(§orbuilder.SectorBuilderConfig{
|
||||
SectorSize: 1024,
|
||||
SealedDir: dir,
|
||||
StagedDir: dir,
|
||||
MetadataDir: dir,
|
||||
SectorSize: sectorSize,
|
||||
SealedDir: sealed,
|
||||
StagedDir: staging,
|
||||
MetadataDir: metadata,
|
||||
Miner: addr,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := io.LimitReader(rand.New(rand.NewSource(42)), 1016)
|
||||
// TODO: Consider fixing
|
||||
store := sector.NewStore(sb, datastore.NewMapDatastore(), func(ctx context.Context) (*sectorbuilder.SealTicket, error) {
|
||||
return §orbuilder.SealTicket{
|
||||
BlockHeight: 5,
|
||||
TicketBytes: [32]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2},
|
||||
}, nil
|
||||
})
|
||||
|
||||
if _, err := sb.AddPiece("foo", 1016, r); err != nil {
|
||||
store.Service()
|
||||
|
||||
dlen := sectorbuilder.UserBytesForSectorSize(sectorSize)
|
||||
|
||||
r := io.LimitReader(rand.New(rand.NewSource(42)), int64(dlen))
|
||||
sid, err := store.AddPiece("foo", dlen, r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := store.SealSector(context.TODO(), sid); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
store := sector.NewStore(sb)
|
||||
store.Service()
|
||||
ssinfo := <-store.Incoming()
|
||||
|
||||
ok, err := sectorbuilder.VerifySeal(1024, ssinfo.CommR[:], ssinfo.CommD[:], ssinfo.CommRStar[:], addr, ssinfo.SectorID, ssinfo.Proof)
|
||||
ok, err := sectorbuilder.VerifySeal(sectorSize, ssinfo.CommR[:], ssinfo.CommD[:], addr, ssinfo.Ticket.TicketBytes[:], ssinfo.SectorID, ssinfo.Proof)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
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": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
|
||||
@ -10663,6 +10668,15 @@
|
||||
"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": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
|
||||
|
@ -13,6 +13,7 @@
|
||||
"react-dom": "^16.8.6",
|
||||
"react-router-dom": "^5.0.1",
|
||||
"react-scripts": "3.0.1",
|
||||
"react-tooltip": "^3.11.1",
|
||||
"rpc-websockets": "^4.5.1",
|
||||
"styled-components": "^3.3.3",
|
||||
"xterm": "^3.14.5",
|
||||
|
@ -1,10 +1,15 @@
|
||||
import React from 'react'
|
||||
import CID from 'cids'
|
||||
import * as multihash from "multihashes";
|
||||
import State from "./State";
|
||||
import methods from "./chain/methods";
|
||||
import ReactTooltip from 'react-tooltip'
|
||||
import * as multihash from "multihashes"
|
||||
import State from "./State"
|
||||
import methods from "./chain/methods"
|
||||
import Fil from "./Fil";
|
||||
|
||||
function truncAddr(addr, len) {
|
||||
if (!addr) {
|
||||
return "<!nil>"
|
||||
}
|
||||
if (addr.length > len) {
|
||||
return <abbr title={addr}>{addr.substr(0, len - 3) + '..'}</abbr>
|
||||
}
|
||||
@ -62,7 +67,7 @@ class Address extends React.Component {
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -117,12 +122,12 @@ class Address extends React.Component {
|
||||
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) {
|
||||
balance = <span/>
|
||||
}
|
||||
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/>
|
||||
}
|
||||
|
||||
@ -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>
|
||||
}
|
||||
|
||||
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,14 +64,21 @@ class Block extends React.Component {
|
||||
<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>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>{messages}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (<Window className="CristalScroll" initialSize={{width: 950, height: 400}} onClose={this.props.onClose} title={`Block ${this.props.cid['/']}`}>
|
||||
return (<Window className="CristalScroll" initialSize={{width: 1050, height: 400}} onClose={this.props.onClose} title={`Block ${this.props.cid['/']}`}>
|
||||
{content}
|
||||
</Window>)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ export class BlockLinks extends React.Component {
|
||||
block = this.props.blocks[k]
|
||||
}
|
||||
|
||||
return <BlockLink key={c + '-' + k} block={block} conn={this.props.conn} cid={c} mountWindow={this.props.mountWindow}/>
|
||||
return <span><BlockLink key={c + '-' + k} block={block} conn={this.props.conn} cid={c} mountWindow={this.props.mountWindow}/> </span>
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -71,10 +71,10 @@ class ChainExplorer extends React.Component {
|
||||
return
|
||||
}
|
||||
if(!base.Blocks) {
|
||||
console.log("base for H is nll blk", h, base)
|
||||
console.log("base for H is nil blk", h, base)
|
||||
return
|
||||
}
|
||||
let cids = base.Blocks.map(b => b.Parents)
|
||||
let cids = base.Blocks.map(b => (b.Parents || []))
|
||||
.reduce((acc, val) => {
|
||||
let out = {...acc}
|
||||
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])))
|
||||
|
||||
if (!blocks[0]) {
|
||||
return
|
||||
}
|
||||
|
||||
cache[h] = {
|
||||
Height: blocks[0].Height,
|
||||
Cids: cids,
|
||||
@ -165,7 +169,7 @@ class ChainExplorer extends React.Component {
|
||||
return <div key={row} className={className}>@{h} {info}</div>
|
||||
})}</div>
|
||||
|
||||
return (<Window onClose={this.props.onClose} title={`Chain Explorer ${this.state.follow ? '(Following)' : ''}`}>
|
||||
return (<Window initialSize={{width: 800}} onClose={this.props.onClose} title={`Chain Explorer ${this.state.follow ? '(Following)' : ''}`}>
|
||||
{content}
|
||||
</Window>)
|
||||
}
|
||||
|
@ -1,18 +1,17 @@
|
||||
import React from 'react';
|
||||
import Address from "./Address";
|
||||
import Window from "./Window";
|
||||
import Fil from "./Fil";
|
||||
|
||||
const dealStates = [
|
||||
"Unknown",
|
||||
"Rejected",
|
||||
"Accepted",
|
||||
"Started",
|
||||
"Failed",
|
||||
"Staged",
|
||||
"Sealing",
|
||||
"Failed",
|
||||
"Complete",
|
||||
"Error",
|
||||
"Expired"
|
||||
]
|
||||
|
||||
|
||||
@ -21,31 +20,43 @@ class Client extends React.Component {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
miners: ["t0101"],
|
||||
ask: {Price: "500000000"},
|
||||
|
||||
kbs: 1,
|
||||
blocks: 12,
|
||||
total: 36000,
|
||||
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()
|
||||
setInterval(this.getDeals, 1325)
|
||||
}
|
||||
|
||||
getDeals = async () => {
|
||||
let miners = await this.props.client.call('Filecoin.StateListMiners', [null])
|
||||
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 });
|
||||
|
||||
makeDeal = async () => {
|
||||
let perBlk = this.state.ask.Price * this.state.kbs * 1000 / (1 << 30)
|
||||
|
||||
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 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)
|
||||
}
|
||||
|
||||
@ -67,23 +78,29 @@ class Client extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
let ppb = Math.round(this.state.total / this.state.blocks * 100) / 100
|
||||
let ppmbb = Math.round(ppb / (this.state.kbs / 1000) * 100) / 100
|
||||
let perBlk = this.state.ask.Price * this.state.kbs * 1000
|
||||
let total = perBlk * this.state.blocks
|
||||
let days = (this.state.blocks * this.state.blockDelay) / 60 / 60 / 24
|
||||
|
||||
let dealMaker = <div hidden={!this.props.pondClient}>
|
||||
<span>Make Deal: </span>
|
||||
<select><option>t0101</option></select>
|
||||
<abbr title="Data length">L:</abbr> <input placeholder="KBs" defaultValue={1} onChange={this.update("kbs")}/>
|
||||
<abbr title="Deal duration">Dur:</abbr><input placeholder="blocks" defaultValue={12} onChange={this.update("blocks")}/>
|
||||
Total: <input placeholder="total price" defaultValue={36000} onChange={this.update("total")}/>
|
||||
<span><abbr title="Price per block">PpB:</abbr> {ppb} </span>
|
||||
<span><abbr title="Price per block-MiB">PpMbB:</abbr> {ppmbb} </span>
|
||||
<div>
|
||||
<span>Make Deal: </span>
|
||||
<select>{this.state.miners.map(m => <option key={m} value={m}>{m}</option>)}</select>
|
||||
<span> Ask: <b><Fil>{this.state.ask.Price}</Fil></b> Fil/Byte/Block</span>
|
||||
</div>
|
||||
<div>
|
||||
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>
|
||||
</div>
|
||||
|
||||
let deals = this.state.deals.map((deal, i) => <div key={i}>
|
||||
<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/> }
|
||||
<ul>
|
||||
<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>)
|
||||
|
||||
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>{dealMaker}</div>
|
||||
<div>{deals}</div>
|
||||
|
@ -5,7 +5,7 @@ import Window from "./Window";
|
||||
function styleForHDiff(max, act) {
|
||||
switch (max - act) {
|
||||
case 0:
|
||||
return {background: '#00aa00'}
|
||||
return {background: '#004400'}
|
||||
case 1:
|
||||
return {background: '#aaaa00'}
|
||||
default:
|
||||
|
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,19 @@
|
||||
import React from 'react'
|
||||
import Window from "./Window";
|
||||
import CID from "cids";
|
||||
import * as multihash from "multihashes";
|
||||
import code from "./chain/code";
|
||||
import Address from "./Address";
|
||||
import Fil from "./Fil";
|
||||
|
||||
class State extends React.Component {
|
||||
byCode = {
|
||||
[code.init]: InitState,
|
||||
[code.power]: PowerState,
|
||||
[code.market]: MarketState,
|
||||
[code.miner]: MinerState,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
@ -9,22 +21,179 @@ class State extends React.Component {
|
||||
}
|
||||
|
||||
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])
|
||||
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() {
|
||||
const content = <div className="State">
|
||||
<div>Balance: {this.state.Balance}</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>
|
||||
</div>
|
||||
let state
|
||||
if(this.byCode[this.state.code]) {
|
||||
const Stelem = this.byCode[this.state.code]
|
||||
state = <Stelem addr={this.props.addr} actor={this.props.actor} 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>
|
||||
}
|
||||
|
||||
return <Window onClose={this.props.onClose} title={`Actor ${this.props.addr} @{this.props.ts.Height}`}>
|
||||
const content = <div className="State">
|
||||
<div>Balance: <Fil>{this.state.Balance}</Fil></div>
|
||||
<div>---</div>
|
||||
{state}
|
||||
</div>
|
||||
return <Window initialSize={{width: 850, height: 400}} onClose={this.props.onClose} title={`Actor ${this.props.addr} ${this.props.tipset && this.props.tipset.Height || ''} ${this.state.code}`}>
|
||||
{content}
|
||||
</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.Client} client={this.props.client} mountWindow={this.props.mountWindow}/></td>
|
||||
<td><Address short={true} addr={this.state.deals[d].Deal.Proposal.Provider} 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.StoragePricePerEpoch*this.state.deals[d].Deal.Proposal.Duration}</td>
|
||||
<td>{this.state.deals[d].Deal.Proposal.Duration}</td>
|
||||
</tr>)}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
class MinerState extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {state: {}, sectorSize: -1, worker: "", networkPower: 0, sectors: {}}
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props
|
||||
|
||||
const state = await this.props.client.call('Filecoin.StateReadState', [this.props.actor, tipset])
|
||||
const sectorSize = await this.props.client.call("Filecoin.StateMinerSectorSize", [this.props.addr, tipset])
|
||||
const worker = await this.props.client.call("Filecoin.StateMinerWorker", [this.props.addr, tipset])
|
||||
|
||||
const tpow = await this.props.client.call("Filecoin.StateMinerPower", [this.props.addr, tipset])
|
||||
const networkPower = tpow.TotalPower
|
||||
|
||||
let sectors = {}
|
||||
|
||||
const sset = await this.props.client.call("Filecoin.StateMinerSectors", [this.props.addr, tipset]) || []
|
||||
const pset = await this.props.client.call("Filecoin.StateMinerProvingSet", [this.props.addr, tipset]) || []
|
||||
|
||||
sset.forEach(s => sectors[s.SectorID] = {...s, sectorSet: true})
|
||||
pset.forEach(s => sectors[s.SectorID] = {...(sectors[s.SectorID] || s), provingSet: true})
|
||||
|
||||
this.setState({state, sectorSize, worker, networkPower, sectors})
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.worker) {
|
||||
return <span>(...)</span>
|
||||
}
|
||||
|
||||
let state = this.state.state.State
|
||||
|
||||
return <div>
|
||||
<div>Worker: <Address addr={this.state.worker} client={this.props.client} mountWindow={this.props.mountWindow}/></div>
|
||||
<div>Sector Size: <b>{this.state.sectorSize/1024}</b> KiB</div>
|
||||
<div>Power: <b>{state.Power}</b> (<b>{state.Power/this.state.networkPower*100}</b>%)</div>
|
||||
<div>Proving Period End: <b>{state.ProvingPeriodEnd}</b></div>
|
||||
<div>
|
||||
<div>----</div>
|
||||
<div>Sectors:</div>
|
||||
<table style={{overflowY: "scroll"}}>
|
||||
<thead>
|
||||
<tr><td>ID</td><td>CommD</td><td>CommR</td><td>SectorSet</td><td>Proving</td></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Object.keys(this.state.sectors).map(sid => <tr key={sid} style={{whiteSpace: 'nowrap'}}>
|
||||
<td>{sid}</td>
|
||||
<td>{this.state.sectors[sid].CommD}</td>
|
||||
<td>{this.state.sectors[sid].CommR}</td>
|
||||
<td>{this.state.sectors[sid].sectorSet ? 'X' : ' '}</td>
|
||||
<td>{this.state.sectors[sid].provingSet ? 'X' : ' '}</td>
|
||||
</tr>)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default State
|
@ -13,6 +13,8 @@ let sealCodes = [
|
||||
"Failed",
|
||||
"Sealing",
|
||||
"Sealed",
|
||||
"Paused",
|
||||
"ReadyForSealing",
|
||||
]
|
||||
|
||||
class StorageNode extends React.Component {
|
||||
@ -122,7 +124,7 @@ class StorageNode extends React.Component {
|
||||
<div>{this.state.statusCounts.map((c, i) => <span key={i}>{sealCodes[i]}: {c} | </span>)}</div>
|
||||
<div>
|
||||
{this.state.staged ? this.state.staged.map((s, i) => (
|
||||
<div key={i}>{s.SectorID} {sealCodes[s.State]}</div>
|
||||
<div key={i}>{s.SectorID} {sealCodes[s.State] || `unk ${s.State}`}</div>
|
||||
)) : <div/>}
|
||||
</div>
|
||||
|
||||
|
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 {
|
||||
"account": [
|
||||
[code.account]: [
|
||||
"Send",
|
||||
"Constructor",
|
||||
"GetAddress",
|
||||
],
|
||||
"smarket": [
|
||||
[code.power]: [
|
||||
"Send",
|
||||
"Constructor",
|
||||
"CreateStorageMiner",
|
||||
@ -15,7 +17,21 @@ export default {
|
||||
"IsMiner",
|
||||
"StorageCollateralForSize"
|
||||
],
|
||||
"sminer": [
|
||||
[code.market]: [
|
||||
"Send",
|
||||
"Constructor",
|
||||
"WithdrawBalance",
|
||||
"AddBalance",
|
||||
"CheckLockedBalance",
|
||||
"PublishStorageDeals",
|
||||
"HandleCronAction",
|
||||
"SettleExpiredDeals",
|
||||
"ProcessStorageDealsPayment",
|
||||
"SlashStorageDealCollateral",
|
||||
"GetLastExpirationFromDealIDs",
|
||||
"ActivateStorageDeals",
|
||||
],
|
||||
[code.miner]: [
|
||||
"Send",
|
||||
"Constructor",
|
||||
"CommitSector",
|
||||
@ -36,7 +52,7 @@ export default {
|
||||
"PaymentVerifyInclusion",
|
||||
"PaymentVerifySector",
|
||||
],
|
||||
"multisig": [
|
||||
[code.multisig]: [
|
||||
"Send",
|
||||
"Constructor",
|
||||
"Propose",
|
||||
@ -48,13 +64,13 @@ export default {
|
||||
"SwapSigner",
|
||||
"ChangeRequirement",
|
||||
],
|
||||
"init": [
|
||||
[code.init]: [
|
||||
"Send",
|
||||
"Constructor",
|
||||
"Exec",
|
||||
"GetIdForAddress"
|
||||
],
|
||||
"paych": [
|
||||
[code.paych]: [
|
||||
"Send",
|
||||
"Constructor",
|
||||
"UpdateChannelState",
|
||||
|
@ -11,3 +11,8 @@ code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||
monospace;
|
||||
}
|
||||
|
||||
input[type=text] {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
@ -235,12 +235,13 @@ func Online() Option {
|
||||
Override(new(*sector.Store), sector.NewStore),
|
||||
Override(new(*sectorblocks.SectorBlocks), sectorblocks.NewSectorBlocks),
|
||||
Override(new(*commitment.Tracker), commitment.NewTracker),
|
||||
Override(new(sector.TicketFn), modules.SealTicketGen),
|
||||
Override(new(*storage.Miner), modules.StorageMiner),
|
||||
|
||||
Override(new(dtypes.StagingDAG), modules.StagingDAG),
|
||||
|
||||
Override(new(*retrieval.Miner), retrieval.NewMiner),
|
||||
Override(new(*deals.Handler), deals.NewHandler),
|
||||
Override(new(*deals.Provider), deals.NewProvider),
|
||||
Override(HandleRetrievalKey, modules.HandleRetrieval),
|
||||
Override(HandleDealsKey, modules.HandleDeals),
|
||||
Override(RunSectorServiceKey, modules.RunSectorService),
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"golang.org/x/xerrors"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
|
||||
"github.com/ipfs/go-blockservice"
|
||||
@ -13,7 +14,6 @@ import (
|
||||
chunker "github.com/ipfs/go-ipfs-chunker"
|
||||
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
||||
files "github.com/ipfs/go-ipfs-files"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
ipld "github.com/ipfs/go-ipld-format"
|
||||
"github.com/ipfs/go-merkledag"
|
||||
"github.com/ipfs/go-unixfs/importer/balanced"
|
||||
@ -53,7 +53,7 @@ type API struct {
|
||||
Filestore dtypes.ClientFilestore `optional:"true"`
|
||||
}
|
||||
|
||||
func (a *API) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, price types.BigInt, blocksDuration uint64) (*cid.Cid, error) {
|
||||
func (a *API) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, epochPrice types.BigInt, blocksDuration uint64) (*cid.Cid, error) {
|
||||
// TODO: make this a param
|
||||
self, err := a.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
@ -76,50 +76,17 @@ func (a *API) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.A
|
||||
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
|
||||
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{
|
||||
Data: data,
|
||||
TotalPrice: total,
|
||||
Duration: blocksDuration,
|
||||
Payment: actors.PaymentInfo{
|
||||
PayChActor: payment.Channel,
|
||||
Payer: self,
|
||||
ChannelMessage: payment.ChannelMessage,
|
||||
Vouchers: payment.Vouchers,
|
||||
},
|
||||
MinerAddress: miner,
|
||||
ClientAddress: self,
|
||||
MinerID: pid,
|
||||
Data: data,
|
||||
PricePerEpoch: epochPrice,
|
||||
ProposalExpiration: math.MaxUint64, // TODO: set something reasonable
|
||||
Duration: blocksDuration,
|
||||
ProviderAddress: miner,
|
||||
Client: 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!)
|
||||
return &c, err
|
||||
}
|
||||
@ -135,14 +102,13 @@ func (a *API) ClientListDeals(ctx context.Context) ([]api.DealInfo, error) {
|
||||
out[k] = api.DealInfo{
|
||||
ProposalCid: v.ProposalCid,
|
||||
State: v.State,
|
||||
Miner: v.Proposal.MinerAddress,
|
||||
Provider: v.Proposal.Provider,
|
||||
|
||||
PieceRef: v.Proposal.PieceRef,
|
||||
CommP: v.Proposal.CommP,
|
||||
Size: v.Proposal.Size,
|
||||
Size: v.Proposal.PieceSize,
|
||||
|
||||
TotalPrice: v.Proposal.TotalPrice,
|
||||
Duration: v.Proposal.Duration,
|
||||
PricePerEpoch: v.Proposal.StoragePricePerEpoch,
|
||||
Duration: v.Proposal.Duration,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,8 @@ func (a *CommonAPI) Version(context.Context) (api.Version, error) {
|
||||
return api.Version{
|
||||
Version: build.Version,
|
||||
APIVersion: build.APIVersion,
|
||||
|
||||
BlockDelay: build.BlockDelay,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
package full
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"github.com/filecoin-project/go-amt-ipld"
|
||||
"strconv"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-hamt-ipld"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"go.uber.org/fx"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@ -33,8 +37,8 @@ type StateAPI struct {
|
||||
Chain *store.ChainStore
|
||||
}
|
||||
|
||||
func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address) ([]*api.SectorInfo, error) {
|
||||
return stmgr.GetMinerSectorSet(ctx, a.StateManager, nil, addr)
|
||||
func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*api.SectorInfo, error) {
|
||||
return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, addr)
|
||||
}
|
||||
|
||||
func (a *StateAPI) StateMinerProvingSet(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*api.SectorInfo, error) {
|
||||
@ -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) {
|
||||
ret, err := a.StateManager.Call(ctx, &types.Message{
|
||||
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
|
||||
return stmgr.GetMinerWorker(ctx, a.StateManager, ts, m)
|
||||
}
|
||||
|
||||
func (a *StateAPI) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) {
|
||||
@ -83,6 +69,10 @@ func (a *StateAPI) StateMinerProvingPeriodEnd(ctx context.Context, actor address
|
||||
return stmgr.GetMinerProvingPeriodEnd(ctx, a.StateManager, ts, actor)
|
||||
}
|
||||
|
||||
func (a *StateAPI) StateMinerSectorSize(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) {
|
||||
return stmgr.GetMinerSectorSize(ctx, a.StateManager, ts, actor)
|
||||
}
|
||||
|
||||
func (a *StateAPI) StatePledgeCollateral(ctx context.Context, ts *types.TipSet) (types.BigInt, error) {
|
||||
param, err := actors.SerializeParams(&actors.PledgeCollateralParams{Size: types.NewInt(0)})
|
||||
if err != nil {
|
||||
@ -90,8 +80,8 @@ func (a *StateAPI) StatePledgeCollateral(ctx context.Context, ts *types.TipSet)
|
||||
}
|
||||
|
||||
ret, aerr := a.StateManager.Call(ctx, &types.Message{
|
||||
From: actors.StorageMarketAddress,
|
||||
To: actors.StorageMarketAddress,
|
||||
From: actors.StoragePowerAddress,
|
||||
To: actors.StoragePowerAddress,
|
||||
Method: actors.SPAMethods.PledgeCollateralForSize,
|
||||
|
||||
Params: param,
|
||||
@ -210,7 +200,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) {
|
||||
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
|
||||
}
|
||||
|
||||
@ -226,3 +216,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) {
|
||||
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
|
||||
}
|
||||
|
@ -7,12 +7,13 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/address"
|
||||
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
||||
"github.com/filecoin-project/lotus/storage"
|
||||
"github.com/filecoin-project/lotus/storage/sector"
|
||||
"github.com/filecoin-project/lotus/storage/sectorblocks"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type StorageMinerAPI struct {
|
||||
@ -31,14 +32,23 @@ func (sm *StorageMinerAPI) ActorAddress(context.Context) (address.Address, error
|
||||
}
|
||||
|
||||
func (sm *StorageMinerAPI) StoreGarbageData(ctx context.Context) (uint64, error) {
|
||||
size := sectorbuilder.UserBytesForSectorSize(build.SectorSize)
|
||||
ssize, err := sm.Miner.SectorSize(ctx)
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("failed to get miner sector size: %w", err)
|
||||
}
|
||||
size := sectorbuilder.UserBytesForSectorSize(ssize)
|
||||
|
||||
// TODO: create a deal
|
||||
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)))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err := sm.Sectors.SealSector(ctx, sectorId); err != nil {
|
||||
return sectorId, err
|
||||
}
|
||||
|
||||
return sectorId, err
|
||||
}
|
||||
|
||||
@ -51,11 +61,6 @@ func (sm *StorageMinerAPI) SectorsList(context.Context) ([]uint64, error) {
|
||||
return sm.SectorBuilder.GetAllStagedSectors()
|
||||
}
|
||||
|
||||
// Seal all staged sectors
|
||||
func (sm *StorageMinerAPI) SectorsStagedSeal(context.Context) error {
|
||||
return sm.SectorBuilder.SealAllStagedSectors()
|
||||
}
|
||||
|
||||
func (sm *StorageMinerAPI) SectorsRefs(context.Context) (map[string][]api.SealedRef, error) {
|
||||
// json can't handle cids as map keys
|
||||
out := map[string][]api.SealedRef{}
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/libp2p/go-libp2p-core/routing"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"go.uber.org/fx"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
@ -38,13 +39,18 @@ func minerAddrFromDS(ds dtypes.MetadataDS) (address.Address, error) {
|
||||
return address.NewFromBytes(maddrb)
|
||||
}
|
||||
|
||||
func SectorBuilderConfig(storagePath string) func(dtypes.MetadataDS) (*sectorbuilder.SectorBuilderConfig, error) {
|
||||
return func(ds dtypes.MetadataDS) (*sectorbuilder.SectorBuilderConfig, error) {
|
||||
func SectorBuilderConfig(storagePath string) func(dtypes.MetadataDS, api.FullNode) (*sectorbuilder.SectorBuilderConfig, error) {
|
||||
return func(ds dtypes.MetadataDS, api api.FullNode) (*sectorbuilder.SectorBuilderConfig, error) {
|
||||
minerAddr, err := minerAddrFromDS(ds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ssize, err := api.StateMinerSectorSize(context.TODO(), minerAddr, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sp, err := homedir.Expand(storagePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -56,7 +62,7 @@ func SectorBuilderConfig(storagePath string) func(dtypes.MetadataDS) (*sectorbui
|
||||
|
||||
sb := §orbuilder.SectorBuilderConfig{
|
||||
Miner: minerAddr,
|
||||
SectorSize: build.SectorSize,
|
||||
SectorSize: ssize,
|
||||
MetadataDir: metadata,
|
||||
SealedDir: sealed,
|
||||
StagedDir: staging,
|
||||
@ -98,13 +104,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)
|
||||
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(context.Context) error {
|
||||
h.Run(ctx)
|
||||
host.SetStreamHandler(deals.ProtocolID, h.HandleStream)
|
||||
host.SetStreamHandler(deals.DealProtocolID, h.HandleStream)
|
||||
host.SetStreamHandler(deals.AskProtocolID, h.HandleAskStream)
|
||||
return nil
|
||||
},
|
||||
@ -157,3 +163,27 @@ func RegisterMiner(lc fx.Lifecycle, ds dtypes.MetadataDS, api api.FullNode) erro
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func SealTicketGen(api api.FullNode) sector.TicketFn {
|
||||
return func(ctx context.Context) (*sectorbuilder.SealTicket, error) {
|
||||
ts, err := api.ChainHead(ctx)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting head ts for SealTicket failed: %w", err)
|
||||
}
|
||||
|
||||
r, err := api.ChainGetRandomness(ctx, ts, nil, build.SealRandomnessLookback)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting randomness for SealTicket failed: %w", err)
|
||||
}
|
||||
|
||||
var tkt [sectorbuilder.CommLen]byte
|
||||
if n := copy(tkt[:], r); n != sectorbuilder.CommLen {
|
||||
return nil, xerrors.Errorf("unexpected randomness len: %d (expected %d)", n, sectorbuilder.CommLen)
|
||||
}
|
||||
|
||||
return §orbuilder.SealTicket{
|
||||
BlockHeight: ts.Height() - build.SealRandomnessLookback,
|
||||
TicketBytes: tkt,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
@ -19,14 +19,14 @@ func (pm *Manager) createPaych(ctx context.Context, from, to address.Address, am
|
||||
|
||||
enc, aerr := actors.SerializeParams(&actors.ExecParams{
|
||||
Params: params,
|
||||
Code: actors.PaymentChannelActorCodeCid,
|
||||
Code: actors.PaymentChannelCodeCid,
|
||||
})
|
||||
if aerr != nil {
|
||||
return address.Undef, cid.Undef, aerr
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
To: actors.InitActorAddress,
|
||||
To: actors.InitAddress,
|
||||
From: from,
|
||||
Value: amt,
|
||||
Method: actors.IAMethods.Exec,
|
||||
|
@ -7,6 +7,13 @@ BOOTSTRAPPERS=( root@147.75.80.17 )
|
||||
|
||||
############
|
||||
|
||||
read -p "You are about to deploy new DevNet, killing bootstrap nodes. Proceed? (y/n)? " r
|
||||
case "$r" in
|
||||
y|Y ) echo "Proceding";;
|
||||
n|N ) exit 0;;
|
||||
* ) exit 1;;
|
||||
esac
|
||||
|
||||
log() {
|
||||
echo -e "\e[33m$1\e[39m"
|
||||
}
|
||||
@ -74,7 +81,7 @@ ssh $GENESIS_HOST 'systemctl start lotus-storage-miner'
|
||||
|
||||
log 'Getting genesis addr info'
|
||||
|
||||
ssh $GENESIS_HOST './lotus net listen' | grep -v '/10' | grep -v '/127' > build/bootstrap/root.pi
|
||||
ssh $GENESIS_HOST 'lotus net listen' | grep -v '/10' | grep -v '/127' > build/bootstrap/root.pi
|
||||
|
||||
log '> Creating bootstrap binaries'
|
||||
make
|
||||
@ -106,5 +113,5 @@ do
|
||||
|
||||
log 'Extracting addr info'
|
||||
|
||||
ssh "$host" './lotus net listen' | grep -v '/10' | grep -v '/127' >> build/bootstrap/bootstrappers.pi
|
||||
ssh "$host" 'lotus net listen' | grep -v '/10' | grep -v '/127' >> build/bootstrap/bootstrappers.pi
|
||||
done
|
||||
|
@ -25,7 +25,7 @@ func init() {
|
||||
var commitmentDsPrefix = datastore.NewKey("/commitments")
|
||||
|
||||
type Tracker struct {
|
||||
commitDs datastore.Datastore
|
||||
commitments datastore.Datastore
|
||||
|
||||
lk sync.Mutex
|
||||
|
||||
@ -34,35 +34,36 @@ type Tracker struct {
|
||||
|
||||
func NewTracker(ds dtypes.MetadataDS) *Tracker {
|
||||
return &Tracker{
|
||||
commitDs: namespace.Wrap(ds, commitmentDsPrefix),
|
||||
waits: map[datastore.Key]chan struct{}{},
|
||||
commitments: namespace.Wrap(ds, commitmentDsPrefix),
|
||||
waits: map[datastore.Key]chan struct{}{},
|
||||
}
|
||||
}
|
||||
|
||||
type commitment struct {
|
||||
Msg cid.Cid
|
||||
DealIDs []uint64
|
||||
Msg cid.Cid
|
||||
}
|
||||
|
||||
func commitmentKey(miner address.Address, sectorId uint64) datastore.Key {
|
||||
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)
|
||||
|
||||
ct.lk.Lock()
|
||||
defer ct.lk.Unlock()
|
||||
|
||||
tracking, err := ct.commitDs.Get(key)
|
||||
tracking, err := ct.commitments.Get(key)
|
||||
switch err {
|
||||
case datastore.ErrNotFound:
|
||||
comm := &commitment{Msg: mcid}
|
||||
comm := &commitment{Msg: commitMsg}
|
||||
commB, err := cbor.DumpObject(comm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ct.commitDs.Put(key, commB); err != nil {
|
||||
if err := ct.commitments.Put(key, commB); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -78,11 +79,11 @@ func (ct *Tracker) TrackCommitSectorMsg(miner address.Address, sectorId uint64,
|
||||
return err
|
||||
}
|
||||
|
||||
if !comm.Msg.Equals(mcid) {
|
||||
return xerrors.Errorf("commitment tracking for miner %s, sector %d: already tracking %s, got another commitment message: %s", miner, sectorId, comm.Msg, 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, 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
|
||||
default:
|
||||
return err
|
||||
@ -94,7 +95,7 @@ func (ct *Tracker) WaitCommit(ctx context.Context, miner address.Address, sector
|
||||
|
||||
ct.lk.Lock()
|
||||
|
||||
tracking, err := ct.commitDs.Get(key)
|
||||
tracking, err := ct.commitments.Get(key)
|
||||
if err != datastore.ErrNotFound {
|
||||
ct.lk.Unlock()
|
||||
|
||||
@ -120,7 +121,7 @@ func (ct *Tracker) WaitCommit(ctx context.Context, miner address.Address, sector
|
||||
|
||||
select {
|
||||
case <-wait:
|
||||
tracking, err := ct.commitDs.Get(key)
|
||||
tracking, err := ct.commitments.Get(key)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to get commitment after waiting: %w", err)
|
||||
}
|
||||
|
@ -9,9 +9,9 @@ import (
|
||||
logging "github.com/ipfs/go-log"
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
"github.com/pkg/errors"
|
||||
"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/address"
|
||||
"github.com/filecoin-project/lotus/chain/events"
|
||||
@ -54,6 +54,7 @@ type storageMinerApi interface {
|
||||
StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error)
|
||||
StateMinerProvingPeriodEnd(context.Context, address.Address, *types.TipSet) (uint64, error)
|
||||
StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*api.SectorInfo, error)
|
||||
StateMinerSectorSize(context.Context, address.Address, *types.TipSet) (uint64, error)
|
||||
StateWaitMsg(context.Context, cid.Cid) (*api.MsgWait, error)
|
||||
|
||||
MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error)
|
||||
@ -121,7 +122,12 @@ func (m *Miner) handlePostingSealedSectors(ctx context.Context) {
|
||||
func (m *Miner) commitSector(ctx context.Context, sinfo sectorbuilder.SectorSealingStatus) error {
|
||||
log.Info("committing sector")
|
||||
|
||||
ok, err := sectorbuilder.VerifySeal(build.SectorSize, sinfo.CommR[:], sinfo.CommD[:], sinfo.CommRStar[:], m.maddr, sinfo.SectorID, sinfo.Proof)
|
||||
ssize, err := m.SectorSize(ctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to check out own sector size: %w", err)
|
||||
}
|
||||
|
||||
ok, err := sectorbuilder.VerifySeal(ssize, sinfo.CommR[:], sinfo.CommD[:], m.maddr, sinfo.Ticket.TicketBytes[:], sinfo.SectorID, sinfo.Proof)
|
||||
if err != nil {
|
||||
log.Error("failed to verify seal we just created: ", err)
|
||||
}
|
||||
@ -129,12 +135,19 @@ func (m *Miner) commitSector(ctx context.Context, sinfo sectorbuilder.SectorSeal
|
||||
log.Error("seal we just created failed verification")
|
||||
}
|
||||
|
||||
params := &actors.CommitSectorParams{
|
||||
SectorID: sinfo.SectorID,
|
||||
CommD: sinfo.CommD[:],
|
||||
CommR: sinfo.CommR[:],
|
||||
CommRStar: sinfo.CommRStar[:],
|
||||
Proof: sinfo.Proof,
|
||||
deals, err := m.secst.DealsForCommit(sinfo.SectorID)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting sector deals failed: %w", err)
|
||||
}
|
||||
|
||||
params := &actors.OnChainSealVerifyInfo{
|
||||
CommD: sinfo.CommD[:],
|
||||
CommR: sinfo.CommR[:],
|
||||
Proof: sinfo.Proof,
|
||||
Epoch: sinfo.Ticket.BlockHeight,
|
||||
|
||||
DealIDs: deals,
|
||||
SectorNumber: sinfo.SectorID,
|
||||
}
|
||||
enc, aerr := actors.SerializeParams(params)
|
||||
if aerr != nil {
|
||||
@ -192,3 +205,8 @@ func (m *Miner) runPreflightChecks(ctx context.Context) error {
|
||||
log.Infof("starting up miner %s, worker addr %s", m.maddr, m.worker)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Miner) SectorSize(ctx context.Context) (uint64, error) {
|
||||
// TODO: cache this
|
||||
return m.api.StateMinerSectorSize(ctx, m.maddr, nil)
|
||||
}
|
||||
|
@ -44,12 +44,12 @@ func (m *Miner) beginPosting(ctx context.Context) {
|
||||
|
||||
m.schedLk.Unlock()
|
||||
|
||||
log.Infof("Scheduling post at height %d", ppe-build.PoSTChallangeTime)
|
||||
log.Infof("Scheduling post at height %d", ppe-build.PoStChallangeTime)
|
||||
err = m.events.ChainAt(m.computePost(m.schedPost), func(ts *types.TipSet) error { // Revert
|
||||
// TODO: Cancel post
|
||||
log.Errorf("TODO: Cancel PoSt, re-run")
|
||||
return nil
|
||||
}, PoStConfidence, ppe-build.PoSTChallangeTime)
|
||||
}, PoStConfidence, ppe-build.PoStChallangeTime)
|
||||
if err != nil {
|
||||
// TODO: This is BAD, figure something out
|
||||
log.Errorf("scheduling PoSt failed: %s", err)
|
||||
@ -82,13 +82,13 @@ func (m *Miner) scheduleNextPost(ppe uint64) {
|
||||
m.schedPost = ppe
|
||||
m.schedLk.Unlock()
|
||||
|
||||
log.Infow("scheduling PoSt", "post-height", ppe-build.PoSTChallangeTime,
|
||||
log.Infow("scheduling PoSt", "post-height", ppe-build.PoStChallangeTime,
|
||||
"height", ts.Height(), "ppe", ppe, "proving-period", provingPeriod)
|
||||
err = m.events.ChainAt(m.computePost(ppe), func(ts *types.TipSet) error { // Revert
|
||||
// TODO: Cancel post
|
||||
log.Errorf("TODO: Cancel PoSt, re-run")
|
||||
return nil
|
||||
}, PoStConfidence, ppe-build.PoSTChallangeTime)
|
||||
}, PoStConfidence, ppe-build.PoStChallangeTime)
|
||||
if err != nil {
|
||||
// TODO: This is BAD, figure something out
|
||||
log.Errorf("scheduling PoSt failed: %+v", err)
|
||||
@ -113,13 +113,13 @@ func (m *Miner) computePost(ppe uint64) func(ts *types.TipSet, curH uint64) erro
|
||||
return xerrors.Errorf("failed to get proving set for miner: %w", err)
|
||||
}
|
||||
|
||||
r, err := m.api.ChainGetRandomness(ctx, ts, nil, int(int64(ts.Height())-int64(ppe)+int64(build.PoSTChallangeTime))) // TODO: review: check math
|
||||
r, err := m.api.ChainGetRandomness(ctx, ts, nil, int(int64(ts.Height())-int64(ppe)+int64(build.PoStChallangeTime)+int64(build.PoStRandomnessLookback))) // TODO: review: check math
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get chain randomness for post (ts=%d; ppe=%d): %w", ts.Height(), ppe, err)
|
||||
}
|
||||
|
||||
log.Infow("running PoSt", "delayed-by",
|
||||
int64(ts.Height())-(int64(ppe)-int64(build.PoSTChallangeTime)),
|
||||
int64(ts.Height())-(int64(ppe)-int64(build.PoStChallangeTime)),
|
||||
"chain-random", r, "ppe", ppe, "height", ts.Height())
|
||||
|
||||
tsStart := time.Now()
|
||||
|
@ -2,24 +2,47 @@ package sector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/filecoin-project/go-sectorbuilder/sealing_state"
|
||||
"golang.org/x/xerrors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"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/lib/sectorbuilder"
|
||||
|
||||
logging "github.com/ipfs/go-log"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cbor.RegisterCborType(dealMapping{})
|
||||
}
|
||||
|
||||
var log = logging.Logger("sectorstore")
|
||||
|
||||
var sectorDealsPrefix = datastore.NewKey("/sectordeals")
|
||||
|
||||
type dealMapping struct {
|
||||
DealIDs []uint64
|
||||
Committed bool
|
||||
}
|
||||
|
||||
type TicketFn func(context.Context) (*sectorbuilder.SealTicket, error)
|
||||
|
||||
// TODO: eventually handle sector storage here instead of in rust-sectorbuilder
|
||||
type Store struct {
|
||||
lk sync.Mutex
|
||||
sb *sectorbuilder.SectorBuilder
|
||||
waitingLk sync.Mutex
|
||||
|
||||
sb *sectorbuilder.SectorBuilder
|
||||
tktFn TicketFn
|
||||
|
||||
dealsLk sync.Mutex
|
||||
deals datastore.Datastore
|
||||
|
||||
waiting map[uint64]chan struct{}
|
||||
incoming []chan sectorbuilder.SectorSealingStatus
|
||||
@ -28,9 +51,11 @@ type Store struct {
|
||||
closeCh chan struct{}
|
||||
}
|
||||
|
||||
func NewStore(sb *sectorbuilder.SectorBuilder) *Store {
|
||||
func NewStore(sb *sectorbuilder.SectorBuilder, ds dtypes.MetadataDS, tktFn TicketFn) *Store {
|
||||
return &Store{
|
||||
sb: sb,
|
||||
tktFn: tktFn,
|
||||
deals: namespace.Wrap(ds, sectorDealsPrefix),
|
||||
waiting: map[uint64]chan struct{}{},
|
||||
closeCh: make(chan struct{}),
|
||||
}
|
||||
@ -44,13 +69,13 @@ func (s *Store) poll() {
|
||||
log.Debug("polling for sealed sectors...")
|
||||
|
||||
// get a list of sectors to poll
|
||||
s.lk.Lock()
|
||||
s.waitingLk.Lock()
|
||||
toPoll := make([]uint64, 0, len(s.waiting))
|
||||
|
||||
for id := range s.waiting {
|
||||
toPoll = append(toPoll, id)
|
||||
}
|
||||
s.lk.Unlock()
|
||||
s.waitingLk.Unlock()
|
||||
|
||||
var done []sectorbuilder.SectorSealingStatus
|
||||
|
||||
@ -68,7 +93,7 @@ func (s *Store) poll() {
|
||||
}
|
||||
|
||||
// send updates
|
||||
s.lk.Lock()
|
||||
s.waitingLk.Lock()
|
||||
for _, sector := range done {
|
||||
watch, ok := s.waiting[sector.SectorID]
|
||||
if ok {
|
||||
@ -79,7 +104,7 @@ func (s *Store) poll() {
|
||||
c <- sector // TODO: ctx!
|
||||
}
|
||||
}
|
||||
s.lk.Unlock()
|
||||
s.waitingLk.Unlock()
|
||||
}
|
||||
|
||||
func (s *Store) service() {
|
||||
@ -90,35 +115,112 @@ func (s *Store) service() {
|
||||
case <-poll:
|
||||
s.poll()
|
||||
case <-s.closeCh:
|
||||
s.lk.Lock()
|
||||
s.waitingLk.Lock()
|
||||
for _, c := range s.incoming {
|
||||
close(c)
|
||||
}
|
||||
s.lk.Unlock()
|
||||
s.waitingLk.Unlock()
|
||||
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, dealIDs ...uint64) (sectorID uint64, err error) {
|
||||
sectorID, err = s.sb.AddPiece(ref, size, r)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
s.lk.Lock()
|
||||
s.waitingLk.Lock()
|
||||
_, exists := s.waiting[sectorID]
|
||||
if !exists { // pieces can share sectors
|
||||
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, dealIDs...)
|
||||
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
|
||||
}
|
||||
|
||||
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) SealSector(ctx context.Context, sectorID uint64) error {
|
||||
tkt, err := s.tktFn(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: That's not async, is it?
|
||||
// - If not then we probably can drop this wait-for-seal hack below
|
||||
_, err = s.sb.SealSector(sectorID, *tkt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) CloseIncoming(c <-chan sectorbuilder.SectorSealingStatus) {
|
||||
s.lk.Lock()
|
||||
s.waitingLk.Lock()
|
||||
var at = -1
|
||||
for i, ch := range s.incoming {
|
||||
if ch == c {
|
||||
@ -126,7 +228,7 @@ func (s *Store) CloseIncoming(c <-chan sectorbuilder.SectorSealingStatus) {
|
||||
}
|
||||
}
|
||||
if at == -1 {
|
||||
s.lk.Unlock()
|
||||
s.waitingLk.Unlock()
|
||||
return
|
||||
}
|
||||
if len(s.incoming) > 1 {
|
||||
@ -135,21 +237,21 @@ func (s *Store) CloseIncoming(c <-chan sectorbuilder.SectorSealingStatus) {
|
||||
s.incoming[last] = nil
|
||||
}
|
||||
s.incoming = s.incoming[:len(s.incoming)-1]
|
||||
s.lk.Unlock()
|
||||
s.waitingLk.Unlock()
|
||||
}
|
||||
|
||||
func (s *Store) Incoming() <-chan sectorbuilder.SectorSealingStatus {
|
||||
ch := make(chan sectorbuilder.SectorSealingStatus, 8)
|
||||
s.lk.Lock()
|
||||
s.waitingLk.Lock()
|
||||
s.incoming = append(s.incoming, ch)
|
||||
s.lk.Unlock()
|
||||
s.waitingLk.Unlock()
|
||||
return ch
|
||||
}
|
||||
|
||||
func (s *Store) WaitSeal(ctx context.Context, sector uint64) (sectorbuilder.SectorSealingStatus, error) {
|
||||
s.lk.Lock()
|
||||
s.waitingLk.Lock()
|
||||
watch, ok := s.waiting[sector]
|
||||
s.lk.Unlock()
|
||||
s.waitingLk.Unlock()
|
||||
if ok {
|
||||
select {
|
||||
case <-watch:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user