Merge pull request #140 from filecoin-project/feat/deal-payments
deals: Wire up client side of payments
This commit is contained in:
commit
6bee253e33
@ -106,7 +106,7 @@ func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams)
|
|||||||
// Set up the actor itself
|
// Set up the actor itself
|
||||||
actor := types.Actor{
|
actor := types.Actor{
|
||||||
Code: p.Code,
|
Code: p.Code,
|
||||||
Balance: vmctx.Message().Value,
|
Balance: types.NewInt(0),
|
||||||
Head: EmptyCBOR,
|
Head: EmptyCBOR,
|
||||||
Nonce: 0,
|
Nonce: 0,
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,15 @@ package actors
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||||
"github.com/filecoin-project/go-lotus/chain/address"
|
"github.com/filecoin-project/go-lotus/chain/address"
|
||||||
"github.com/filecoin-project/go-lotus/chain/types"
|
"github.com/filecoin-project/go-lotus/chain/types"
|
||||||
"github.com/filecoin-project/go-lotus/lib/sectorbuilder"
|
"github.com/filecoin-project/go-lotus/lib/sectorbuilder"
|
||||||
"golang.org/x/xerrors"
|
"github.com/ipfs/go-cid"
|
||||||
|
"github.com/ipfs/go-hamt-ipld"
|
||||||
cid "github.com/ipfs/go-cid"
|
|
||||||
hamt "github.com/ipfs/go-hamt-ipld"
|
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -21,6 +19,9 @@ func init() {
|
|||||||
cbor.RegisterCborType(CommitSectorParams{})
|
cbor.RegisterCborType(CommitSectorParams{})
|
||||||
cbor.RegisterCborType(MinerInfo{})
|
cbor.RegisterCborType(MinerInfo{})
|
||||||
cbor.RegisterCborType(SubmitPoStParams{})
|
cbor.RegisterCborType(SubmitPoStParams{})
|
||||||
|
cbor.RegisterCborType(PieceInclVoucherData{})
|
||||||
|
cbor.RegisterCborType(InclusionProof{})
|
||||||
|
cbor.RegisterCborType(PaymentVerifyParams{})
|
||||||
}
|
}
|
||||||
|
|
||||||
var ProvingPeriodDuration = uint64(2 * 60) // an hour, for now
|
var ProvingPeriodDuration = uint64(2 * 60) // an hour, for now
|
||||||
@ -112,9 +113,13 @@ type maMethods struct {
|
|||||||
GetSectorSize uint64
|
GetSectorSize uint64
|
||||||
UpdatePeerID uint64
|
UpdatePeerID uint64
|
||||||
ChangeWorker uint64
|
ChangeWorker uint64
|
||||||
|
IsSlashed uint64
|
||||||
|
IsLate uint64
|
||||||
|
PaymentVerifyInclusion uint64
|
||||||
|
PaymentVerifySector uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
var MAMethods = maMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
|
var MAMethods = maMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}
|
||||||
|
|
||||||
func (sma StorageMinerActor) Exports() []interface{} {
|
func (sma StorageMinerActor) Exports() []interface{} {
|
||||||
return []interface{}{
|
return []interface{}{
|
||||||
@ -132,6 +137,10 @@ func (sma StorageMinerActor) Exports() []interface{} {
|
|||||||
12: sma.GetSectorSize,
|
12: sma.GetSectorSize,
|
||||||
13: sma.UpdatePeerID,
|
13: sma.UpdatePeerID,
|
||||||
//14: sma.ChangeWorker,
|
//14: sma.ChangeWorker,
|
||||||
|
//15: sma.IsSlashed,
|
||||||
|
//16: sma.IsLate,
|
||||||
|
17: sma.PaymentVerifyInclusion,
|
||||||
|
18: sma.PaymentVerifySector,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,6 +385,38 @@ func AddToSectorSet(ctx context.Context, cst *hamt.CborIpldStore, ss cid.Cid, se
|
|||||||
return ssroot, nil
|
return ssroot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetFromSectorSet(ctx context.Context, cst *hamt.CborIpldStore, ss cid.Cid, sectorID types.BigInt) (bool, []byte, []byte, ActorError) {
|
||||||
|
nd, err := hamt.LoadNode(ctx, cst, ss)
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, nil, aerrors.Escalate(err, "could not load HAMT node")
|
||||||
|
}
|
||||||
|
|
||||||
|
infoIf, err := nd.Find(ctx, sectorID.String())
|
||||||
|
if err == hamt.ErrNotFound {
|
||||||
|
return false, nil, nil, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, nil, aerrors.Escalate(err, "failed to find sector in sector set")
|
||||||
|
}
|
||||||
|
|
||||||
|
infoB, ok := infoIf.([]byte)
|
||||||
|
if !ok {
|
||||||
|
return false, nil, nil, aerrors.Escalate(xerrors.New("casting infoIf to []byte failed"), "") // TODO: Review: how to create aerrror without retcode?
|
||||||
|
}
|
||||||
|
|
||||||
|
var comms [][]byte // [ [commR], [commD] ]
|
||||||
|
err = cbor.DecodeInto(infoB, &comms)
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, nil, aerrors.Escalate(err, "failed to decode sector set entry")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(comms) != 2 {
|
||||||
|
return false, nil, nil, aerrors.Escalate(xerrors.New("sector set entry should only have 2 elements"), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, comms[0], comms[1], nil
|
||||||
|
}
|
||||||
|
|
||||||
func ValidatePoRep(maddr address.Address, ssize types.BigInt, params *CommitSectorParams) (bool, ActorError) {
|
func ValidatePoRep(maddr address.Address, ssize types.BigInt, params *CommitSectorParams) (bool, ActorError) {
|
||||||
ok, err := sectorbuilder.VerifySeal(ssize.Uint64(), params.CommR, params.CommD, params.CommRStar, maddr, params.SectorID.Uint64(), params.Proof)
|
ok, err := sectorbuilder.VerifySeal(ssize.Uint64(), params.CommR, params.CommD, params.CommRStar, maddr, params.SectorID.Uint64(), params.Proof)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -493,3 +534,86 @@ func (sma StorageMinerActor) GetSectorSize(act *types.Actor, vmctx types.VMConte
|
|||||||
|
|
||||||
return mi.SectorSize.Bytes(), nil
|
return mi.SectorSize.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PaymentVerifyParams struct {
|
||||||
|
Extra []byte
|
||||||
|
Proof []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type PieceInclVoucherData struct { // TODO: Update spec at https://github.com/filecoin-project/specs/blob/master/actors.md#paymentverify
|
||||||
|
CommP []byte
|
||||||
|
PieceSize types.BigInt
|
||||||
|
}
|
||||||
|
|
||||||
|
type InclusionProof struct {
|
||||||
|
Sector types.BigInt // 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.Escalate(err, "failed to decode storage voucher data for verification")
|
||||||
|
}
|
||||||
|
var proof InclusionProof
|
||||||
|
if err := cbor.DecodeInto(params.Proof, &proof); err != nil {
|
||||||
|
return nil, aerrors.Escalate(err, "failed to decode storage payment proof")
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, _, commD, aerr := GetFromSectorSet(context.TODO(), vmctx.Ipld(), self.Sectors, proof.Sector)
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil, aerrors.New(1, "miner does not have required sector")
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := sectorbuilder.VerifyPieceInclusionProof(mi.SectorSize.Uint64(), voucherData.PieceSize.Uint64(), voucherData.CommP, commD, params.Proof)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.Escalate(err, "verify piece inclusion proof failed")
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil, aerrors.New(2, "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.Ipld(), self.Sectors, sector)
|
||||||
|
if aerr != nil {
|
||||||
|
return nil, aerr
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil, aerrors.New(2, "miner does not have required sector")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
@ -183,43 +183,56 @@ func (c *Client) waitAccept(s inet.Stream, proposal StorageDealProposal, minerID
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Start(ctx context.Context, data cid.Cid, totalPrice types.BigInt, from address.Address, miner address.Address, minerID peer.ID, blocksDuration uint64) (cid.Cid, error) {
|
type ClientDealProposal struct {
|
||||||
|
Data cid.Cid
|
||||||
|
|
||||||
|
TotalPrice types.BigInt
|
||||||
|
Duration uint64
|
||||||
|
|
||||||
|
Payment actors.PaymentInfo
|
||||||
|
|
||||||
|
MinerAddress address.Address
|
||||||
|
ClientAddress 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)
|
commP, size, err := c.commP(ctx, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dummyCid, _ := cid.Parse("bafkqaaa")
|
return &actors.PieceInclVoucherData{
|
||||||
|
CommP: commP,
|
||||||
|
PieceSize: types.NewInt(uint64(size)),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Start(ctx context.Context, p ClientDealProposal, vd *actors.PieceInclVoucherData) (cid.Cid, error) {
|
||||||
// TODO: use data
|
// TODO: use data
|
||||||
proposal := StorageDealProposal{
|
proposal := StorageDealProposal{
|
||||||
PieceRef: data.String(),
|
PieceRef: p.Data.String(),
|
||||||
SerializationMode: SerializationUnixFs,
|
SerializationMode: SerializationUnixFs,
|
||||||
CommP: commP[:],
|
CommP: vd.CommP[:],
|
||||||
Size: uint64(size),
|
Size: vd.PieceSize.Uint64(),
|
||||||
TotalPrice: totalPrice,
|
TotalPrice: p.TotalPrice,
|
||||||
Duration: blocksDuration,
|
Duration: p.Duration,
|
||||||
Payment: actors.PaymentInfo{
|
Payment: p.Payment,
|
||||||
PayChActor: address.Address{},
|
MinerAddress: p.MinerAddress,
|
||||||
Payer: address.Address{},
|
ClientAddress: p.ClientAddress,
|
||||||
ChannelMessage: dummyCid,
|
|
||||||
Vouchers: nil,
|
|
||||||
},
|
|
||||||
MinerAddress: miner,
|
|
||||||
ClientAddress: from,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := c.h.NewStream(ctx, minerID, ProtocolID)
|
s, err := c.h.NewStream(ctx, p.MinerID, ProtocolID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
defer s.Reset() // TODO: handle other updates
|
defer s.Reset() // TODO: handle other updates
|
||||||
|
|
||||||
if err := c.sendProposal(s, proposal, from); err != nil {
|
if err := c.sendProposal(s, proposal, p.ClientAddress); err != nil {
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
deal, err := c.waitAccept(s, proposal, minerID)
|
deal, err := c.waitAccept(s, proposal, p.MinerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,14 @@ func VerifySeal(sectorSize uint64, commR, commD, commRStar []byte, proverID addr
|
|||||||
return sectorbuilder.VerifySeal(sectorSize, commRa, commDa, commRStara, proverIDa, sectorIDa, proof)
|
return sectorbuilder.VerifySeal(sectorSize, commRa, commDa, commRStara, proverIDa, sectorIDa, proof)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func VerifyPieceInclusionProof(sectorSize uint64, pieceSize uint64, commP []byte, commD []byte, proof []byte) (bool, error) {
|
||||||
|
var commPa, commDa [32]byte
|
||||||
|
copy(commPa[:], commP)
|
||||||
|
copy(commDa[:], commD)
|
||||||
|
|
||||||
|
return sectorbuilder.VerifyPieceInclusionProof(sectorSize, pieceSize, commPa, commDa, proof)
|
||||||
|
}
|
||||||
|
|
||||||
func VerifyPost(sectorSize uint64, sortedCommRs [][CommLen]byte, challengeSeed [CommLen]byte, proofs [][]byte, faults []uint64) (bool, error) {
|
func VerifyPost(sectorSize uint64, sortedCommRs [][CommLen]byte, challengeSeed [CommLen]byte, proofs [][]byte, faults []uint64) (bool, error) {
|
||||||
// sectorbuilder.VerifyPost()
|
// sectorbuilder.VerifyPost()
|
||||||
panic("no")
|
panic("no")
|
||||||
|
@ -59,7 +59,12 @@ class Address extends React.Component {
|
|||||||
addr = <a href="#" onClick={this.openState}>{addr}</a>
|
addr = <a href="#" onClick={this.openState}>{addr}</a>
|
||||||
}
|
}
|
||||||
|
|
||||||
return <span>{addr}: {this.state.balance} {actInfo} {add1k}</span>
|
let balance = <span>: {this.state.balance}</span>
|
||||||
|
if(this.props.nobalance) {
|
||||||
|
balance = <span></span>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <span>{addr}{balance} {actInfo} {add1k}</span>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,10 +16,14 @@
|
|||||||
background: #f9be77;
|
background: #f9be77;
|
||||||
user-select: text;
|
user-select: text;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
min-width: 40em;
|
min-width: 50em;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.FullNode-voucher {
|
||||||
|
padding-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.StorageNode {
|
.StorageNode {
|
||||||
background: #f9be77;
|
background: #f9be77;
|
||||||
user-select: text;
|
user-select: text;
|
||||||
|
@ -36,21 +36,17 @@ class FullNode extends React.Component {
|
|||||||
|
|
||||||
const tipset = await this.props.client.call("Filecoin.ChainHead", [])
|
const tipset = await this.props.client.call("Filecoin.ChainHead", [])
|
||||||
|
|
||||||
const addrs = await this.props.client.call('Filecoin.WalletList', [])
|
let addrs = await this.props.client.call('Filecoin.WalletList', [])
|
||||||
let defaultAddr = ""
|
let defaultAddr = ""
|
||||||
if (addrs.length > 0) {
|
if (addrs.length > 0) {
|
||||||
defaultAddr = await this.props.client.call('Filecoin.WalletDefaultAddress', [])
|
defaultAddr = await this.props.client.call('Filecoin.WalletDefaultAddress', [])
|
||||||
}
|
}
|
||||||
|
let paychs = await this.props.client.call('Filecoin.PaychList', [])
|
||||||
/* const balances = await addrss.map(async addr => {
|
if(!paychs)
|
||||||
let balance = 0
|
paychs = []
|
||||||
try {
|
const vouchers = await Promise.all(paychs.map(paych => {
|
||||||
balance = await this.props.client.call('Filecoin.WalletBalance', [addr])
|
return this.props.client.call('Filecoin.PaychVoucherList', [paych])
|
||||||
} catch {
|
}))
|
||||||
balance = -1
|
|
||||||
}
|
|
||||||
return [addr, balance]
|
|
||||||
}).reduce(awaitListReducer, Promise.resolve([]))*/
|
|
||||||
|
|
||||||
this.setState(() => ({
|
this.setState(() => ({
|
||||||
id: id,
|
id: id,
|
||||||
@ -59,6 +55,9 @@ class FullNode extends React.Component {
|
|||||||
tipset: tipset,
|
tipset: tipset,
|
||||||
|
|
||||||
addrs: addrs,
|
addrs: addrs,
|
||||||
|
paychs: paychs,
|
||||||
|
vouchers: vouchers,
|
||||||
|
|
||||||
defaultAddr: defaultAddr}))
|
defaultAddr: defaultAddr}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,6 +117,23 @@ class FullNode extends React.Component {
|
|||||||
}
|
}
|
||||||
return <div key={addr}>{line}</div>
|
return <div key={addr}>{line}</div>
|
||||||
})
|
})
|
||||||
|
let paychannels = this.state.paychs.map((addr, ak) => {
|
||||||
|
const line = <Address client={this.props.client} add1k={this.add1k} addr={addr} mountWindow={this.props.mountWindow}/>
|
||||||
|
const vouchers = this.state.vouchers[ak].map(voucher => {
|
||||||
|
let extra = <span></span>
|
||||||
|
if(voucher.Extra) {
|
||||||
|
extra = <span>Verif: <<b><Address nobalance={true} client={this.props.client} addr={voucher.Extra.Actor} mountWindow={this.props.mountWindow}/>M{voucher.Extra.Method}</b>></span>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div key={voucher.Nonce} className="FullNode-voucher">
|
||||||
|
Voucher Nonce:<b>{voucher.Nonce}</b> Lane:<b>{voucher.Lane}</b> Amt:<b>{voucher.Amount}</b> TL:<b>{voucher.TimeLock}</b> MinCl:<b>{voucher.MinCloseHeight}</b> {extra}
|
||||||
|
</div>
|
||||||
|
})
|
||||||
|
return <div key={addr}>
|
||||||
|
{line}
|
||||||
|
{vouchers}
|
||||||
|
</div>
|
||||||
|
})
|
||||||
|
|
||||||
runtime = (
|
runtime = (
|
||||||
<div>
|
<div>
|
||||||
@ -130,6 +146,7 @@ class FullNode extends React.Component {
|
|||||||
<div>
|
<div>
|
||||||
<div>Balances: [New <a href="#" onClick={this.newScepAddr}>[Secp256k1]</a>]</div>
|
<div>Balances: [New <a href="#" onClick={this.newScepAddr}>[Secp256k1]</a>]</div>
|
||||||
<div>{addresses}</div>
|
<div>{addresses}</div>
|
||||||
|
<div>{paychannels}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -47,11 +47,13 @@ type FullNodeAPI struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *FullNodeAPI) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, price types.BigInt, blocksDuration uint64) (*cid.Cid, error) {
|
func (a *FullNodeAPI) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, price types.BigInt, blocksDuration uint64) (*cid.Cid, error) {
|
||||||
|
// TODO: make this a param
|
||||||
self, err := a.WalletDefaultAddress(ctx)
|
self, err := a.WalletDefaultAddress(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get miner peerID
|
||||||
msg := &types.Message{
|
msg := &types.Message{
|
||||||
To: miner,
|
To: miner,
|
||||||
From: miner,
|
From: miner,
|
||||||
@ -67,8 +69,59 @@ func (a *FullNodeAPI) ClientStartDeal(ctx context.Context, data cid.Cid, miner a
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vd, err := a.DealClient.VerifyParams(ctx, data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
voucherData, err := cbor.DumpObject(vd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup payments
|
||||||
total := types.BigMul(price, types.NewInt(blocksDuration))
|
total := types.BigMul(price, types.NewInt(blocksDuration))
|
||||||
c, err := a.DealClient.Start(ctx, data, total, self, miner, pid, blocksDuration)
|
|
||||||
|
// TODO: at least ping the miner before creating paych / locking the money
|
||||||
|
paych, paychMsg, err := a.paychCreate(ctx, self, miner, total)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
voucher := types.SignedVoucher{
|
||||||
|
// TimeLock: 0, // TODO: do we want to use this somehow?
|
||||||
|
Extra: &types.ModVerifyParams{
|
||||||
|
Actor: miner,
|
||||||
|
Method: actors.MAMethods.PaymentVerifyInclusion,
|
||||||
|
Data: voucherData,
|
||||||
|
},
|
||||||
|
Lane: 0,
|
||||||
|
Amount: total,
|
||||||
|
MinCloseHeight: blocksDuration, // TODO: some way to start this after initial piece inclusion by actor? (also, at least add current height)
|
||||||
|
}
|
||||||
|
|
||||||
|
sv, err := a.paychVoucherCreate(ctx, paych, voucher)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
proposal := deals.ClientDealProposal{
|
||||||
|
Data: data,
|
||||||
|
TotalPrice: total,
|
||||||
|
Duration: blocksDuration,
|
||||||
|
Payment: actors.PaymentInfo{
|
||||||
|
PayChActor: paych,
|
||||||
|
Payer: self,
|
||||||
|
ChannelMessage: paychMsg,
|
||||||
|
Vouchers: []types.SignedVoucher{*sv},
|
||||||
|
},
|
||||||
|
MinerAddress: miner,
|
||||||
|
ClientAddress: self,
|
||||||
|
MinerID: pid,
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := a.DealClient.Start(ctx, proposal, vd)
|
||||||
|
// TODO: send updated voucher with PaymentVerifySector for cheaper validation (validate the sector the miner sent us first!)
|
||||||
return &c, err
|
return &c, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,15 +473,19 @@ func (a *FullNodeAPI) StateMinerProvingSet(ctx context.Context, addr address.Add
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *FullNodeAPI) PaychCreate(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, error) {
|
func (a *FullNodeAPI) PaychCreate(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, error) {
|
||||||
|
act, _, err := a.paychCreate(ctx, from, to, amt)
|
||||||
|
return act, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *FullNodeAPI) paychCreate(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, cid.Cid, error) {
|
||||||
params, aerr := actors.SerializeParams(&actors.PCAConstructorParams{To: to})
|
params, aerr := actors.SerializeParams(&actors.PCAConstructorParams{To: to})
|
||||||
if aerr != nil {
|
if aerr != nil {
|
||||||
return address.Undef, aerr
|
return address.Undef, cid.Undef, aerr
|
||||||
}
|
}
|
||||||
|
|
||||||
nonce, err := a.MpoolGetNonce(ctx, from)
|
nonce, err := a.MpoolGetNonce(ctx, from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return address.Undef, err
|
return address.Undef, cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
enc, err := actors.SerializeParams(&actors.ExecParams{
|
enc, err := actors.SerializeParams(&actors.ExecParams{
|
||||||
@ -449,12 +506,12 @@ func (a *FullNodeAPI) PaychCreate(ctx context.Context, from, to address.Address,
|
|||||||
|
|
||||||
ser, err := msg.Serialize()
|
ser, err := msg.Serialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return address.Undef, err
|
return address.Undef, cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sig, err := a.WalletSign(ctx, from, ser)
|
sig, err := a.WalletSign(ctx, from, ser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return address.Undef, err
|
return address.Undef, cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
smsg := &types.SignedMessage{
|
smsg := &types.SignedMessage{
|
||||||
@ -463,28 +520,28 @@ func (a *FullNodeAPI) PaychCreate(ctx context.Context, from, to address.Address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := a.MpoolPush(ctx, smsg); err != nil {
|
if err := a.MpoolPush(ctx, smsg); err != nil {
|
||||||
return address.Undef, err
|
return address.Undef, cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mwait, err := a.ChainWaitMsg(ctx, smsg.Cid())
|
mwait, err := a.ChainWaitMsg(ctx, smsg.Cid())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return address.Undef, err
|
return address.Undef, cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if mwait.Receipt.ExitCode != 0 {
|
if mwait.Receipt.ExitCode != 0 {
|
||||||
return address.Undef, fmt.Errorf("payment channel creation failed (exit code %d)", mwait.Receipt.ExitCode)
|
return address.Undef, cid.Undef, fmt.Errorf("payment channel creation failed (exit code %d)", mwait.Receipt.ExitCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
paychaddr, err := address.NewFromBytes(mwait.Receipt.Return)
|
paychaddr, err := address.NewFromBytes(mwait.Receipt.Return)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return address.Undef, err
|
return address.Undef, cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.PaychMgr.TrackOutboundChannel(ctx, paychaddr); err != nil {
|
if err := a.PaychMgr.TrackOutboundChannel(ctx, paychaddr); err != nil {
|
||||||
return address.Undef, err
|
return address.Undef, cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return paychaddr, nil
|
return paychaddr, msg.Cid(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *FullNodeAPI) PaychList(ctx context.Context) ([]address.Address, error) {
|
func (a *FullNodeAPI) PaychList(ctx context.Context) ([]address.Address, error) {
|
||||||
@ -551,21 +608,22 @@ func (a *FullNodeAPI) PaychVoucherAdd(ctx context.Context, ch address.Address, s
|
|||||||
// actual additional value of this voucher will only be the difference between
|
// actual additional value of this voucher will only be the difference between
|
||||||
// the two.
|
// the two.
|
||||||
func (a *FullNodeAPI) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*types.SignedVoucher, error) {
|
func (a *FullNodeAPI) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*types.SignedVoucher, error) {
|
||||||
|
return a.paychVoucherCreate(ctx, pch, types.SignedVoucher{Amount: amt, Lane: lane})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *FullNodeAPI) paychVoucherCreate(ctx context.Context, pch address.Address, voucher types.SignedVoucher) (*types.SignedVoucher, error) {
|
||||||
ci, err := a.PaychMgr.GetChannelInfo(pch)
|
ci, err := a.PaychMgr.GetChannelInfo(pch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nonce, err := a.PaychMgr.NextNonceForLane(ctx, pch, lane)
|
nonce, err := a.PaychMgr.NextNonceForLane(ctx, pch, voucher.Lane)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sv := &types.SignedVoucher{
|
sv := &voucher
|
||||||
Lane: lane,
|
sv.Nonce = nonce
|
||||||
Nonce: nonce,
|
|
||||||
Amount: amt,
|
|
||||||
}
|
|
||||||
|
|
||||||
vb, err := sv.SigningBytes()
|
vb, err := sv.SigningBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user