262 lines
6.3 KiB
Go
262 lines
6.3 KiB
Go
package paychmgr
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/filecoin-project/lotus/lib/sigs"
|
|
|
|
"github.com/filecoin-project/specs-actors/actors/crypto"
|
|
|
|
cbornode "github.com/ipfs/go-ipld-cbor"
|
|
|
|
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
|
|
"github.com/filecoin-project/go-address"
|
|
"github.com/filecoin-project/lotus/api"
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
|
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
"github.com/ipfs/go-cid"
|
|
)
|
|
|
|
type mockManagerAPI struct {
|
|
*mockStateManager
|
|
*mockPaychAPI
|
|
}
|
|
|
|
func newMockManagerAPI() *mockManagerAPI {
|
|
return &mockManagerAPI{
|
|
mockStateManager: newMockStateManager(),
|
|
mockPaychAPI: newMockPaychAPI(),
|
|
}
|
|
}
|
|
|
|
type mockPchState struct {
|
|
actor *types.Actor
|
|
state paych.State
|
|
}
|
|
|
|
type mockStateManager struct {
|
|
lk sync.Mutex
|
|
accountState map[address.Address]account.State
|
|
paychState map[address.Address]mockPchState
|
|
store adt.Store
|
|
response *api.InvocResult
|
|
lastCall *types.Message
|
|
}
|
|
|
|
func newMockStateManager() *mockStateManager {
|
|
return &mockStateManager{
|
|
accountState: make(map[address.Address]account.State),
|
|
paychState: make(map[address.Address]mockPchState),
|
|
store: adt.WrapStore(context.Background(), cbornode.NewMemCborStore()),
|
|
}
|
|
}
|
|
|
|
func (sm *mockStateManager) AdtStore(ctx context.Context) adt.Store {
|
|
return sm.store
|
|
}
|
|
|
|
func (sm *mockStateManager) setAccountState(a address.Address, state account.State) {
|
|
sm.lk.Lock()
|
|
defer sm.lk.Unlock()
|
|
sm.accountState[a] = state
|
|
}
|
|
|
|
func (sm *mockStateManager) setPaychState(a address.Address, actor *types.Actor, state paych.State) {
|
|
sm.lk.Lock()
|
|
defer sm.lk.Unlock()
|
|
sm.paychState[a] = mockPchState{actor, state}
|
|
}
|
|
|
|
func (sm *mockStateManager) storeLaneStates(laneStates map[uint64]paych.LaneState) (cid.Cid, error) {
|
|
arr := adt.MakeEmptyArray(sm.store)
|
|
for i, ls := range laneStates {
|
|
ls := ls
|
|
if err := arr.Set(i, &ls); err != nil {
|
|
return cid.Undef, err
|
|
}
|
|
}
|
|
return arr.Root()
|
|
}
|
|
|
|
func (sm *mockStateManager) LoadActorState(ctx context.Context, a address.Address, out interface{}, ts *types.TipSet) (*types.Actor, error) {
|
|
sm.lk.Lock()
|
|
defer sm.lk.Unlock()
|
|
|
|
if outState, ok := out.(*account.State); ok {
|
|
*outState = sm.accountState[a]
|
|
return nil, nil
|
|
}
|
|
if outState, ok := out.(*paych.State); ok {
|
|
info := sm.paychState[a]
|
|
*outState = info.state
|
|
return info.actor, nil
|
|
}
|
|
panic(fmt.Sprintf("unexpected state type %v", out))
|
|
}
|
|
|
|
func (sm *mockStateManager) setCallResponse(response *api.InvocResult) {
|
|
sm.lk.Lock()
|
|
defer sm.lk.Unlock()
|
|
|
|
sm.response = response
|
|
}
|
|
|
|
func (sm *mockStateManager) getLastCall() *types.Message {
|
|
sm.lk.Lock()
|
|
defer sm.lk.Unlock()
|
|
|
|
return sm.lastCall
|
|
}
|
|
|
|
func (sm *mockStateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) {
|
|
sm.lk.Lock()
|
|
defer sm.lk.Unlock()
|
|
|
|
sm.lastCall = msg
|
|
|
|
return sm.response, nil
|
|
}
|
|
|
|
type waitingCall struct {
|
|
response chan types.MessageReceipt
|
|
}
|
|
|
|
type waitingResponse struct {
|
|
receipt types.MessageReceipt
|
|
done chan struct{}
|
|
}
|
|
|
|
type mockPaychAPI struct {
|
|
lk sync.Mutex
|
|
messages map[cid.Cid]*types.SignedMessage
|
|
waitingCalls map[cid.Cid]*waitingCall
|
|
waitingResponses map[cid.Cid]*waitingResponse
|
|
wallet map[address.Address]struct{}
|
|
signingKey []byte
|
|
}
|
|
|
|
func newMockPaychAPI() *mockPaychAPI {
|
|
return &mockPaychAPI{
|
|
messages: make(map[cid.Cid]*types.SignedMessage),
|
|
waitingCalls: make(map[cid.Cid]*waitingCall),
|
|
waitingResponses: make(map[cid.Cid]*waitingResponse),
|
|
wallet: make(map[address.Address]struct{}),
|
|
}
|
|
}
|
|
|
|
func (pchapi *mockPaychAPI) StateWaitMsg(ctx context.Context, mcid cid.Cid, confidence uint64) (*api.MsgLookup, error) {
|
|
pchapi.lk.Lock()
|
|
|
|
response := make(chan types.MessageReceipt)
|
|
|
|
if response, ok := pchapi.waitingResponses[mcid]; ok {
|
|
defer pchapi.lk.Unlock()
|
|
defer func() {
|
|
go close(response.done)
|
|
}()
|
|
|
|
delete(pchapi.waitingResponses, mcid)
|
|
return &api.MsgLookup{Receipt: response.receipt}, nil
|
|
}
|
|
|
|
pchapi.waitingCalls[mcid] = &waitingCall{response: response}
|
|
pchapi.lk.Unlock()
|
|
|
|
receipt := <-response
|
|
return &api.MsgLookup{Receipt: receipt}, nil
|
|
}
|
|
|
|
func (pchapi *mockPaychAPI) receiveMsgResponse(mcid cid.Cid, receipt types.MessageReceipt) {
|
|
pchapi.lk.Lock()
|
|
|
|
if call, ok := pchapi.waitingCalls[mcid]; ok {
|
|
defer pchapi.lk.Unlock()
|
|
|
|
delete(pchapi.waitingCalls, mcid)
|
|
call.response <- receipt
|
|
return
|
|
}
|
|
|
|
done := make(chan struct{})
|
|
pchapi.waitingResponses[mcid] = &waitingResponse{receipt: receipt, done: done}
|
|
|
|
pchapi.lk.Unlock()
|
|
|
|
<-done
|
|
}
|
|
|
|
// Send success response for any waiting calls
|
|
func (pchapi *mockPaychAPI) close() {
|
|
pchapi.lk.Lock()
|
|
defer pchapi.lk.Unlock()
|
|
|
|
success := types.MessageReceipt{
|
|
ExitCode: 0,
|
|
Return: []byte{},
|
|
}
|
|
for mcid, call := range pchapi.waitingCalls {
|
|
delete(pchapi.waitingCalls, mcid)
|
|
call.response <- success
|
|
}
|
|
}
|
|
|
|
func (pchapi *mockPaychAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) {
|
|
pchapi.lk.Lock()
|
|
defer pchapi.lk.Unlock()
|
|
|
|
smsg := &types.SignedMessage{Message: *msg}
|
|
pchapi.messages[smsg.Cid()] = smsg
|
|
return smsg, nil
|
|
}
|
|
|
|
func (pchapi *mockPaychAPI) pushedMessages(c cid.Cid) *types.SignedMessage {
|
|
pchapi.lk.Lock()
|
|
defer pchapi.lk.Unlock()
|
|
|
|
return pchapi.messages[c]
|
|
}
|
|
|
|
func (pchapi *mockPaychAPI) pushedMessageCount() int {
|
|
pchapi.lk.Lock()
|
|
defer pchapi.lk.Unlock()
|
|
|
|
return len(pchapi.messages)
|
|
}
|
|
|
|
func (pchapi *mockPaychAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
|
return addr, nil
|
|
}
|
|
|
|
func (pchapi *mockPaychAPI) WalletHas(ctx context.Context, addr address.Address) (bool, error) {
|
|
pchapi.lk.Lock()
|
|
defer pchapi.lk.Unlock()
|
|
|
|
_, ok := pchapi.wallet[addr]
|
|
return ok, nil
|
|
}
|
|
|
|
func (pchapi *mockPaychAPI) addWalletAddress(addr address.Address) {
|
|
pchapi.lk.Lock()
|
|
defer pchapi.lk.Unlock()
|
|
|
|
pchapi.wallet[addr] = struct{}{}
|
|
}
|
|
|
|
func (pchapi *mockPaychAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*crypto.Signature, error) {
|
|
pchapi.lk.Lock()
|
|
defer pchapi.lk.Unlock()
|
|
|
|
return sigs.Sign(crypto.SigTypeSecp256k1, pchapi.signingKey, msg)
|
|
}
|
|
|
|
func (pchapi *mockPaychAPI) addSigningKey(key []byte) {
|
|
pchapi.lk.Lock()
|
|
defer pchapi.lk.Unlock()
|
|
|
|
pchapi.signingKey = key
|
|
}
|