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
|
||||
actor := types.Actor{
|
||||
Code: p.Code,
|
||||
Balance: vmctx.Message().Value,
|
||||
Balance: types.NewInt(0),
|
||||
Head: EmptyCBOR,
|
||||
Nonce: 0,
|
||||
}
|
||||
|
@ -2,17 +2,15 @@ package actors
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
"github.com/filecoin-project/go-lotus/lib/sectorbuilder"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-hamt-ipld"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -21,6 +19,9 @@ func init() {
|
||||
cbor.RegisterCborType(CommitSectorParams{})
|
||||
cbor.RegisterCborType(MinerInfo{})
|
||||
cbor.RegisterCborType(SubmitPoStParams{})
|
||||
cbor.RegisterCborType(PieceInclVoucherData{})
|
||||
cbor.RegisterCborType(InclusionProof{})
|
||||
cbor.RegisterCborType(PaymentVerifyParams{})
|
||||
}
|
||||
|
||||
var ProvingPeriodDuration = uint64(2 * 60) // an hour, for now
|
||||
@ -98,23 +99,27 @@ type StorageMinerConstructorParams struct {
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
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{} {
|
||||
return []interface{}{
|
||||
@ -132,6 +137,10 @@ func (sma StorageMinerActor) Exports() []interface{} {
|
||||
12: sma.GetSectorSize,
|
||||
13: sma.UpdatePeerID,
|
||||
//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
|
||||
}
|
||||
|
||||
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) {
|
||||
ok, err := sectorbuilder.VerifySeal(ssize.Uint64(), params.CommR, params.CommD, params.CommRStar, maddr, params.SectorID.Uint64(), params.Proof)
|
||||
if err != nil {
|
||||
@ -493,3 +534,86 @@ func (sma StorageMinerActor) GetSectorSize(act *types.Actor, vmctx types.VMConte
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
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
|
||||
proposal := StorageDealProposal{
|
||||
PieceRef: data.String(),
|
||||
PieceRef: p.Data.String(),
|
||||
SerializationMode: SerializationUnixFs,
|
||||
CommP: commP[:],
|
||||
Size: uint64(size),
|
||||
TotalPrice: totalPrice,
|
||||
Duration: blocksDuration,
|
||||
Payment: actors.PaymentInfo{
|
||||
PayChActor: address.Address{},
|
||||
Payer: address.Address{},
|
||||
ChannelMessage: dummyCid,
|
||||
Vouchers: nil,
|
||||
},
|
||||
MinerAddress: miner,
|
||||
ClientAddress: from,
|
||||
CommP: vd.CommP[:],
|
||||
Size: vd.PieceSize.Uint64(),
|
||||
TotalPrice: p.TotalPrice,
|
||||
Duration: p.Duration,
|
||||
Payment: p.Payment,
|
||||
MinerAddress: p.MinerAddress,
|
||||
ClientAddress: p.ClientAddress,
|
||||
}
|
||||
|
||||
s, err := c.h.NewStream(ctx, minerID, ProtocolID)
|
||||
s, err := c.h.NewStream(ctx, p.MinerID, ProtocolID)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
deal, err := c.waitAccept(s, proposal, minerID)
|
||||
deal, err := c.waitAccept(s, proposal, p.MinerID)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
// sectorbuilder.VerifyPost()
|
||||
panic("no")
|
||||
|
@ -59,7 +59,12 @@ class Address extends React.Component {
|
||||
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;
|
||||
user-select: text;
|
||||
font-family: monospace;
|
||||
min-width: 40em;
|
||||
min-width: 50em;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.FullNode-voucher {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.StorageNode {
|
||||
background: #f9be77;
|
||||
user-select: text;
|
||||
|
@ -36,21 +36,17 @@ class FullNode extends React.Component {
|
||||
|
||||
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 = ""
|
||||
if (addrs.length > 0) {
|
||||
defaultAddr = await this.props.client.call('Filecoin.WalletDefaultAddress', [])
|
||||
}
|
||||
|
||||
/* const balances = await addrss.map(async addr => {
|
||||
let balance = 0
|
||||
try {
|
||||
balance = await this.props.client.call('Filecoin.WalletBalance', [addr])
|
||||
} catch {
|
||||
balance = -1
|
||||
}
|
||||
return [addr, balance]
|
||||
}).reduce(awaitListReducer, Promise.resolve([]))*/
|
||||
let paychs = await this.props.client.call('Filecoin.PaychList', [])
|
||||
if(!paychs)
|
||||
paychs = []
|
||||
const vouchers = await Promise.all(paychs.map(paych => {
|
||||
return this.props.client.call('Filecoin.PaychVoucherList', [paych])
|
||||
}))
|
||||
|
||||
this.setState(() => ({
|
||||
id: id,
|
||||
@ -59,6 +55,9 @@ class FullNode extends React.Component {
|
||||
tipset: tipset,
|
||||
|
||||
addrs: addrs,
|
||||
paychs: paychs,
|
||||
vouchers: vouchers,
|
||||
|
||||
defaultAddr: defaultAddr}))
|
||||
}
|
||||
|
||||
@ -118,6 +117,23 @@ class FullNode extends React.Component {
|
||||
}
|
||||
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 = (
|
||||
<div>
|
||||
@ -130,6 +146,7 @@ class FullNode extends React.Component {
|
||||
<div>
|
||||
<div>Balances: [New <a href="#" onClick={this.newScepAddr}>[Secp256k1]</a>]</div>
|
||||
<div>{addresses}</div>
|
||||
<div>{paychannels}</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) {
|
||||
// TODO: make this a param
|
||||
self, err := a.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// get miner peerID
|
||||
msg := &types.Message{
|
||||
To: miner,
|
||||
From: miner,
|
||||
@ -67,8 +69,59 @@ func (a *FullNodeAPI) ClientStartDeal(ctx context.Context, data cid.Cid, miner 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))
|
||||
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
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
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})
|
||||
if aerr != nil {
|
||||
return address.Undef, aerr
|
||||
return address.Undef, cid.Undef, aerr
|
||||
}
|
||||
|
||||
nonce, err := a.MpoolGetNonce(ctx, from)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
return address.Undef, cid.Undef, err
|
||||
}
|
||||
|
||||
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()
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
return address.Undef, cid.Undef, err
|
||||
}
|
||||
|
||||
sig, err := a.WalletSign(ctx, from, ser)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
return address.Undef, cid.Undef, err
|
||||
}
|
||||
|
||||
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 {
|
||||
return address.Undef, err
|
||||
return address.Undef, cid.Undef, err
|
||||
}
|
||||
|
||||
mwait, err := a.ChainWaitMsg(ctx, smsg.Cid())
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
return address.Undef, cid.Undef, err
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
return address.Undef, cid.Undef, err
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -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
|
||||
// the two.
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonce, err := a.PaychMgr.NextNonceForLane(ctx, pch, lane)
|
||||
nonce, err := a.PaychMgr.NextNonceForLane(ctx, pch, voucher.Lane)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sv := &types.SignedVoucher{
|
||||
Lane: lane,
|
||||
Nonce: nonce,
|
||||
Amount: amt,
|
||||
}
|
||||
sv := &voucher
|
||||
sv.Nonce = nonce
|
||||
|
||||
vb, err := sv.SigningBytes()
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user