132 lines
3.2 KiB
Go
132 lines
3.2 KiB
Go
|
package paych
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
|
||
|
"github.com/ipfs/go-cid"
|
||
|
|
||
|
"github.com/filecoin-project/go-lotus/chain/actors"
|
||
|
"github.com/filecoin-project/go-lotus/chain/address"
|
||
|
"github.com/filecoin-project/go-lotus/chain/types"
|
||
|
)
|
||
|
|
||
|
func (pm *Manager) createPaych(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, cid.Undef, aerr
|
||
|
}
|
||
|
|
||
|
nonce, err := pm.mpool.MpoolGetNonce(ctx, from)
|
||
|
if err != nil {
|
||
|
return address.Undef, cid.Undef, err
|
||
|
}
|
||
|
|
||
|
enc, err := actors.SerializeParams(&actors.ExecParams{
|
||
|
Params: params,
|
||
|
Code: actors.PaymentChannelActorCodeCid,
|
||
|
})
|
||
|
|
||
|
msg := &types.Message{
|
||
|
To: actors.InitActorAddress,
|
||
|
From: from,
|
||
|
Value: amt,
|
||
|
Nonce: nonce,
|
||
|
Method: actors.IAMethods.Exec,
|
||
|
Params: enc,
|
||
|
GasLimit: types.NewInt(1000000),
|
||
|
GasPrice: types.NewInt(0),
|
||
|
}
|
||
|
|
||
|
smsg, err := pm.wallet.WalletSignMessage(ctx, from, msg)
|
||
|
if err != nil {
|
||
|
return address.Undef, cid.Undef, err
|
||
|
}
|
||
|
|
||
|
if err := pm.mpool.MpoolPush(ctx, smsg); err != nil {
|
||
|
return address.Undef, cid.Undef, err
|
||
|
}
|
||
|
|
||
|
mcid := smsg.Cid()
|
||
|
|
||
|
// TODO: wait outside the store lock!
|
||
|
// (tricky because we need to setup channel tracking before we know it's address)
|
||
|
mwait, err := pm.chain.ChainWaitMsg(ctx, mcid)
|
||
|
if err != nil {
|
||
|
return address.Undef, cid.Undef, err
|
||
|
}
|
||
|
|
||
|
if mwait.Receipt.ExitCode != 0 {
|
||
|
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, cid.Undef, err
|
||
|
}
|
||
|
|
||
|
if err := pm.TrackOutboundChannel(ctx, paychaddr); err != nil {
|
||
|
return address.Undef, cid.Undef, err
|
||
|
}
|
||
|
|
||
|
return paychaddr, mcid, nil
|
||
|
}
|
||
|
|
||
|
func (pm *Manager) addFunds(ctx context.Context, ch address.Address, from address.Address, amt types.BigInt) error {
|
||
|
nonce, err := pm.mpool.MpoolGetNonce(ctx, from)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
msg := &types.Message{
|
||
|
To: ch,
|
||
|
From: from,
|
||
|
Value: amt,
|
||
|
Nonce: nonce,
|
||
|
Method: 0,
|
||
|
GasLimit: types.NewInt(1000000),
|
||
|
GasPrice: types.NewInt(0),
|
||
|
}
|
||
|
|
||
|
smsg, err := pm.wallet.WalletSignMessage(ctx, from, msg)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if err := pm.mpool.MpoolPush(ctx, smsg); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
mwait, err := pm.chain.ChainWaitMsg(ctx, smsg.Cid()) // TODO: wait outside the store lock!
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if mwait.Receipt.ExitCode != 0 {
|
||
|
return fmt.Errorf("voucher channel creation failed: adding funds (exit code %d)", mwait.Receipt.ExitCode)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (pm *Manager) GetPaych(ctx context.Context, from, to address.Address, ensureFree types.BigInt) (address.Address, cid.Cid, error) {
|
||
|
pm.store.lk.Lock()
|
||
|
defer pm.store.lk.Unlock()
|
||
|
|
||
|
ch, err := pm.store.findChan(func(ci *ChannelInfo) bool {
|
||
|
if ci.Direction != DirOutbound {
|
||
|
return false
|
||
|
}
|
||
|
return ci.Control == from && ci.Target == to
|
||
|
})
|
||
|
if err != nil {
|
||
|
return address.Undef, cid.Undef, err
|
||
|
}
|
||
|
if ch != address.Undef {
|
||
|
// TODO: Track available funds
|
||
|
return ch, cid.Undef, pm.addFunds(ctx, ch, from, ensureFree)
|
||
|
}
|
||
|
|
||
|
return pm.createPaych(ctx, from, to, ensureFree)
|
||
|
}
|