2020-08-05 01:16:25 +00:00
|
|
|
package market
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"math/rand"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
|
|
|
"github.com/filecoin-project/go-address"
|
2020-09-07 03:49:10 +00:00
|
|
|
"github.com/filecoin-project/go-state-types/abi"
|
|
|
|
"github.com/filecoin-project/go-state-types/crypto"
|
2020-10-08 20:32:54 +00:00
|
|
|
|
2020-10-08 01:09:33 +00:00
|
|
|
tutils "github.com/filecoin-project/specs-actors/v2/support/testing"
|
2020-08-05 01:16:25 +00:00
|
|
|
|
|
|
|
"github.com/filecoin-project/lotus/api"
|
|
|
|
"github.com/filecoin-project/lotus/chain/actors"
|
2020-09-23 06:18:52 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
2020-08-05 01:16:25 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
type fakeAPI struct {
|
|
|
|
returnedBalance api.MarketBalance
|
|
|
|
returnedBalanceErr error
|
|
|
|
signature crypto.Signature
|
|
|
|
receivedMessage *types.Message
|
|
|
|
pushMessageErr error
|
2020-08-06 01:33:11 +00:00
|
|
|
lookupIDErr error
|
2020-08-05 01:16:25 +00:00
|
|
|
}
|
|
|
|
|
2020-08-06 01:33:11 +00:00
|
|
|
func (fapi *fakeAPI) StateLookupID(_ context.Context, addr address.Address, _ types.TipSetKey) (address.Address, error) {
|
|
|
|
return addr, fapi.lookupIDErr
|
|
|
|
}
|
2020-08-05 01:16:25 +00:00
|
|
|
func (fapi *fakeAPI) StateMarketBalance(context.Context, address.Address, types.TipSetKey) (api.MarketBalance, error) {
|
|
|
|
return fapi.returnedBalance, fapi.returnedBalanceErr
|
|
|
|
}
|
|
|
|
|
2020-08-12 20:17:21 +00:00
|
|
|
func (fapi *fakeAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) {
|
2020-08-05 01:16:25 +00:00
|
|
|
fapi.receivedMessage = msg
|
|
|
|
return &types.SignedMessage{
|
|
|
|
Message: *msg,
|
|
|
|
Signature: fapi.signature,
|
|
|
|
}, fapi.pushMessageErr
|
|
|
|
}
|
|
|
|
|
|
|
|
func addFundsMsg(toAdd abi.TokenAmount, addr address.Address, wallet address.Address) *types.Message {
|
|
|
|
params, _ := actors.SerializeParams(&addr)
|
|
|
|
return &types.Message{
|
2020-09-23 06:18:52 +00:00
|
|
|
To: market.Address,
|
2020-08-05 01:16:25 +00:00
|
|
|
From: wallet,
|
|
|
|
Value: toAdd,
|
2020-10-08 20:32:54 +00:00
|
|
|
Method: market.Methods.AddBalance,
|
2020-08-05 01:16:25 +00:00
|
|
|
Params: params,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type expectedResult struct {
|
2020-10-09 20:18:43 +00:00
|
|
|
addAmt abi.TokenAmount
|
|
|
|
shouldAdd bool
|
|
|
|
err error
|
|
|
|
cachedAvailable abi.TokenAmount
|
2020-08-05 01:16:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAddFunds(t *testing.T) {
|
|
|
|
ctx := context.Background()
|
|
|
|
testCases := map[string]struct {
|
|
|
|
returnedBalanceErr error
|
|
|
|
returnedBalance api.MarketBalance
|
|
|
|
addAmounts []abi.TokenAmount
|
|
|
|
pushMessageErr error
|
|
|
|
expectedResults []expectedResult
|
2020-08-06 01:33:11 +00:00
|
|
|
lookupIDErr error
|
2020-08-05 01:16:25 +00:00
|
|
|
}{
|
|
|
|
"succeeds, trivial case": {
|
|
|
|
returnedBalance: api.MarketBalance{Escrow: abi.NewTokenAmount(0), Locked: abi.NewTokenAmount(0)},
|
|
|
|
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
|
|
|
expectedResults: []expectedResult{
|
|
|
|
{
|
|
|
|
addAmt: abi.NewTokenAmount(100),
|
|
|
|
shouldAdd: true,
|
|
|
|
err: nil,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"succeeds, money already present": {
|
|
|
|
returnedBalance: api.MarketBalance{Escrow: abi.NewTokenAmount(150), Locked: abi.NewTokenAmount(50)},
|
|
|
|
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
|
|
|
expectedResults: []expectedResult{
|
|
|
|
{
|
2020-10-09 20:18:43 +00:00
|
|
|
shouldAdd: false,
|
|
|
|
err: nil,
|
|
|
|
cachedAvailable: abi.NewTokenAmount(100),
|
2020-08-05 01:16:25 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"succeeds, multiple adds": {
|
|
|
|
returnedBalance: api.MarketBalance{Escrow: abi.NewTokenAmount(150), Locked: abi.NewTokenAmount(50)},
|
|
|
|
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100), abi.NewTokenAmount(200), abi.NewTokenAmount(250), abi.NewTokenAmount(250)},
|
|
|
|
expectedResults: []expectedResult{
|
|
|
|
{
|
|
|
|
shouldAdd: false,
|
|
|
|
err: nil,
|
|
|
|
},
|
|
|
|
{
|
2020-10-09 20:18:43 +00:00
|
|
|
addAmt: abi.NewTokenAmount(100),
|
|
|
|
shouldAdd: true,
|
|
|
|
err: nil,
|
|
|
|
cachedAvailable: abi.NewTokenAmount(200),
|
2020-08-05 01:16:25 +00:00
|
|
|
},
|
|
|
|
{
|
2020-10-09 20:18:43 +00:00
|
|
|
addAmt: abi.NewTokenAmount(50),
|
|
|
|
shouldAdd: true,
|
|
|
|
err: nil,
|
|
|
|
cachedAvailable: abi.NewTokenAmount(250),
|
2020-08-05 01:16:25 +00:00
|
|
|
},
|
|
|
|
{
|
2020-10-09 20:18:43 +00:00
|
|
|
shouldAdd: false,
|
|
|
|
err: nil,
|
|
|
|
cachedAvailable: abi.NewTokenAmount(250),
|
2020-08-05 01:16:25 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"error on market balance": {
|
|
|
|
returnedBalanceErr: errors.New("something went wrong"),
|
|
|
|
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
|
|
|
expectedResults: []expectedResult{
|
|
|
|
{
|
|
|
|
err: errors.New("something went wrong"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"error on push message": {
|
|
|
|
returnedBalance: api.MarketBalance{Escrow: abi.NewTokenAmount(0), Locked: abi.NewTokenAmount(0)},
|
|
|
|
pushMessageErr: errors.New("something went wrong"),
|
|
|
|
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
|
|
|
expectedResults: []expectedResult{
|
|
|
|
{
|
2020-10-09 20:18:43 +00:00
|
|
|
err: errors.New("something went wrong"),
|
|
|
|
cachedAvailable: abi.NewTokenAmount(0),
|
2020-08-05 01:16:25 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-08-06 01:33:11 +00:00
|
|
|
"error looking up address": {
|
|
|
|
lookupIDErr: errors.New("something went wrong"),
|
|
|
|
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
|
|
|
expectedResults: []expectedResult{
|
|
|
|
{
|
|
|
|
err: errors.New("something went wrong"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-08-05 01:16:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for testCase, data := range testCases {
|
2020-08-20 04:49:10 +00:00
|
|
|
//nolint:scopelint
|
2020-08-05 01:16:25 +00:00
|
|
|
t.Run(testCase, func(t *testing.T) {
|
|
|
|
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
sig := make([]byte, 100)
|
|
|
|
_, err := rand.Read(sig)
|
|
|
|
require.NoError(t, err)
|
|
|
|
fapi := &fakeAPI{
|
|
|
|
returnedBalance: data.returnedBalance,
|
|
|
|
returnedBalanceErr: data.returnedBalanceErr,
|
|
|
|
signature: crypto.Signature{
|
|
|
|
Type: crypto.SigTypeUnknown,
|
|
|
|
Data: sig,
|
|
|
|
},
|
|
|
|
pushMessageErr: data.pushMessageErr,
|
2020-08-06 01:33:11 +00:00
|
|
|
lookupIDErr: data.lookupIDErr,
|
2020-08-05 01:16:25 +00:00
|
|
|
}
|
|
|
|
fundMgr := newFundMgr(fapi)
|
|
|
|
addr := tutils.NewIDAddr(t, uint64(rand.Uint32()))
|
|
|
|
wallet := tutils.NewIDAddr(t, uint64(rand.Uint32()))
|
|
|
|
for i, amount := range data.addAmounts {
|
|
|
|
fapi.receivedMessage = nil
|
|
|
|
_, err := fundMgr.EnsureAvailable(ctx, addr, wallet, amount)
|
|
|
|
expected := data.expectedResults[i]
|
|
|
|
if expected.err == nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
if expected.shouldAdd {
|
|
|
|
expectedMessage := addFundsMsg(expected.addAmt, addr, wallet)
|
|
|
|
require.Equal(t, expectedMessage, fapi.receivedMessage)
|
|
|
|
} else {
|
|
|
|
require.Nil(t, fapi.receivedMessage)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
require.EqualError(t, err, expected.err.Error())
|
|
|
|
}
|
2020-10-09 20:18:43 +00:00
|
|
|
|
|
|
|
if !expected.cachedAvailable.Nil() {
|
|
|
|
require.Equal(t, expected.cachedAvailable, fundMgr.available[addr])
|
|
|
|
}
|
2020-08-05 01:16:25 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|