Skip to content

Commit da278cd

Browse files
committed
support cross net/chain payment
1 parent 882542b commit da278cd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2243
-475
lines changed

celersdk/pay.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func (mc *Client) SendToken(tk *Token, receiver string, amtWei string, noteTypeU
3333
Value: noteValueByte,
3434
}
3535
payID, err := mc.c.AddBooleanPay(
36-
xfer, []*entity.Condition{}, mc.c.GetCurrentBlockNumberUint64()+cPayTimeout, note)
36+
xfer, []*entity.Condition{}, mc.c.GetCurrentBlockNumberUint64()+cPayTimeout, note, 0)
3737
if err != nil {
3838
log.Errorln("SendToken:", err)
3939
return ctype.ZeroPayIDHex, err
@@ -60,7 +60,7 @@ func (mc *Client) SendTokenWithCondition(tk *Token, receiver string, amtWei stri
6060
return ctype.ZeroPayIDHex, err
6161
}
6262
payID, err := mc.c.AddBooleanPay(
63-
xfer, []*entity.Condition{condition}, mc.c.GetCurrentBlockNumberUint64()+uint64(timeout), nil /*note*/)
63+
xfer, []*entity.Condition{condition}, mc.c.GetCurrentBlockNumberUint64()+uint64(timeout), nil /*note*/, 0)
6464
if err != nil {
6565
log.Errorln("SendTokenWithCondition:", err)
6666
return ctype.ZeroPayIDHex, err
@@ -153,12 +153,11 @@ func (mc *Client) SendConditionalPayment(
153153
for i, condition := range conditions {
154154
entityConditions[i] = conditionToEntityCondition(condition)
155155
}
156-
payID, err :=
157-
mc.c.AddBooleanPay(
158-
transfer,
159-
entityConditions,
160-
mc.c.GetCurrentBlockNumberUint64()+uint64(timeout),
161-
note)
156+
payID, err := mc.c.AddBooleanPay(
157+
transfer,
158+
entityConditions,
159+
mc.c.GetCurrentBlockNumberUint64()+uint64(timeout),
160+
note, 0)
162161
if err != nil {
163162
log.Error(err)
164163
return ctype.ZeroPayIDHex, err

client/api.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ func (c *CelerClient) InstantiateChannelForToken(token *entity.TokenInfo, appcb
126126
// AddBooleanPay creates a condpay based on args, and call cnode to send CondPayRequest
127127
// returns payId or err
128128
func (c *CelerClient) AddBooleanPay(
129-
xfer *entity.TokenTransfer, conds []*entity.Condition, resolveDeadline uint64, note *any.Any) (ctype.PayIDType, error) {
129+
xfer *entity.TokenTransfer, conds []*entity.Condition, resolveDeadline uint64, note *any.Any, dstNetId uint64) (ctype.PayIDType, error) {
130130

131131
if xfer == nil || xfer.Receiver == nil || xfer.Receiver.Account == nil {
132132
return ctype.ZeroPayID, common.ErrInvalidArg
@@ -151,7 +151,7 @@ func (c *CelerClient) AddBooleanPay(
151151
var payID ctype.PayIDType
152152
var cnoderr error
153153
for i := 0; i < 10; i++ {
154-
payID, cnoderr = c.cNode.AddBooleanPay(pay, note)
154+
payID, cnoderr = c.cNode.AddBooleanPay(pay, note, dstNetId)
155155
if cnoderr != common.ErrPendingSimplex {
156156
break
157157
}

cnode/pay.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ func (c *CNode) OnSendToken(sendCallback event.OnSendingTokenCallback) {
4747
}
4848

4949
// Similar to EstablishCondPayOnToken. This will add hash lock condition to pay condition and set time stamp.
50-
func (c *CNode) AddBooleanPay(newPay *entity.ConditionalPay, note *any.Any) (ctype.PayIDType, error) {
50+
func (c *CNode) AddBooleanPay(newPay *entity.ConditionalPay, note *any.Any, dstNetId uint64) (ctype.PayIDType, error) {
5151
if utils.GetTokenAddr(newPay.TransferFunc.MaxTransfer.Token) == ctype.InvalidTokenAddr {
5252
return ctype.ZeroPayID, common.ErrUnknownTokenType
5353
}
5454

5555
newPay.PayTimestamp = uint64(time.Now().UnixNano())
56-
directPay := c.messager.IsDirectPay(newPay, ctype.ZeroAddr)
56+
directPay := c.messager.IsDirectPay(newPay, ctype.ZeroAddr, dstNetId)
5757

5858
// Skip prepending HL if it's already there or for direct-pay.
5959
var hashStr, secretStr string
@@ -87,7 +87,25 @@ func (c *CNode) AddBooleanPay(newPay *entity.ConditionalPay, note *any.Any) (cty
8787
if err != nil {
8888
return ctype.ZeroPayID, err
8989
}
90-
err = c.messager.SendCondPayRequest(newPayBytes, note, logEntry)
90+
91+
var xnet *rpc.CrossNetPay
92+
if dstNetId != 0 {
93+
myNetId, err2 := c.dal.GetNetId()
94+
if err != nil {
95+
return ctype.ZeroPayID, fmt.Errorf("GetNetId err %w", err2)
96+
}
97+
if myNetId != dstNetId { // cross network payment
98+
xnet = &rpc.CrossNetPay{
99+
SrcNetId: myNetId,
100+
DstNetId: dstNetId,
101+
OriginalPay: newPayBytes,
102+
}
103+
logEntry.Xnet.SrcNetId = myNetId
104+
logEntry.Xnet.DstNetId = dstNetId
105+
logEntry.Xnet.State = pem.CrossNetPayState_XNET_SRC
106+
}
107+
}
108+
err = c.messager.SendCondPayRequest(newPayBytes, note, xnet, logEntry)
91109
if err != nil {
92110
logEntry.Error = append(logEntry.Error, err.Error())
93111
payID = ctype.ZeroPayID

common/structs/types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ const (
6565
ChanState_OPENED int = 3
6666
ChanState_SETTLING int = 4
6767
ChanState_CLOSED int = 5
68+
69+
CrossNetPay_NULL int = 0
70+
CrossNetPay_SRC int = 1
71+
CrossNetPay_DST int = 2
72+
CrossNetPay_INGRESS int = 3
73+
CrossNetPay_EGRESS int = 4
6874
)
6975

7076
type DepositJob struct {

delegate/delegate.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
)
1919

2020
type delegateProcess interface {
21-
AddBooleanPay(pay *entity.ConditionalPay, note *any.Any) (ctype.PayIDType, error)
21+
AddBooleanPay(pay *entity.ConditionalPay, note *any.Any, dstNetId uint64) (ctype.PayIDType, error)
2222
GetCurrentBlockNumber() *big.Int
2323
}
2424

@@ -154,7 +154,7 @@ func (m *DelegateManager) sendToken(dst ctype.Addr, lumpsum *lumpSum) error {
154154
ResolveTimeout: config.PayResolveTimeout,
155155
}
156156

157-
payID, err := m.process.AddBooleanPay(pay, note)
157+
payID, err := m.process.AddBooleanPay(pay, note, 0)
158158
if err != nil {
159159
log.Errorln(err, utils.PrintConditionalPay(pay), note)
160160
return err

handlers/msghdl/handle_cond_pay_receipt.go

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,16 @@ func (h *CelerMsgHandler) HandleCondPayReceipt(frame *common.MsgFrame) error {
3333
if dst != h.nodeConfig.GetOnChainAddr() {
3434
_, peer, err := h.routeForwarder.LookupIngressChannelOnPay(payID)
3535
if err != nil {
36-
return fmt.Errorf("LookupIngressChannelOnPay err %w", err)
36+
if (err == common.ErrPayNotFound || err == common.ErrPayNoIngress) && receipt.GetOriginalPayId() != nil {
37+
// proceed as crossnet payment
38+
logEntry.Xnet.OriginalPayId = ctype.Bytes2Hex(receipt.GetOriginalPayId())
39+
peer, err = h.forwardCrossNetPayReceipt(frame)
40+
if err != nil {
41+
return err
42+
}
43+
} else {
44+
return fmt.Errorf("LookupIngressChannelOnPay err: %w", err)
45+
}
3746
}
3847
logEntry.MsgTo = ctype.Addr2Hex(peer)
3948
log.Debugf("Forwarding cond pay receipt to %x, next hop %x", dst, peer)
@@ -95,6 +104,9 @@ func (h *CelerMsgHandler) HandleCondPayReceipt(frame *common.MsgFrame) error {
95104
PayId: receipt.PayId,
96105
Secret: secretBytes,
97106
}
107+
if receipt.GetOriginalPayId() != nil {
108+
secretMsg.OriginalPayId = payID.Bytes()
109+
}
98110
toAddr := pay.GetDest()
99111
if delegateDescription != nil {
100112
toAddr = delegateDescription.GetDelegator()
@@ -145,3 +157,37 @@ func (h *CelerMsgHandler) verifyDelegationProof(
145157
}
146158
return nil
147159
}
160+
161+
func (h *CelerMsgHandler) forwardCrossNetPayReceipt(frame *common.MsgFrame) (ctype.Addr, error) {
162+
logEntry := frame.LogEntry
163+
receipt := frame.Message.GetCondPayReceipt()
164+
logEntry.Xnet.OriginalPayId = ctype.Bytes2Hex(receipt.GetOriginalPayId())
165+
166+
payID, state, bridgeAddr, found, err :=
167+
h.dal.GetCrossNetInfoByOrignalPayID(ctype.Bytes2PayID(receipt.GetOriginalPayId()))
168+
if err != nil {
169+
return ctype.ZeroAddr, fmt.Errorf("GetCrossNetInfo err %w", err)
170+
}
171+
if !found {
172+
return ctype.ZeroAddr, fmt.Errorf("GetCrossNetInfo %w", common.ErrPayNotFound)
173+
}
174+
logEntry.PayId = ctype.PayID2Hex(payID)
175+
176+
if state == enums.CrossNetPay_INGRESS {
177+
return bridgeAddr, nil
178+
} else if state == enums.CrossNetPay_EGRESS {
179+
_, peer, err := h.routeForwarder.LookupIngressChannelOnPay(payID)
180+
if err != nil {
181+
return ctype.ZeroAddr, fmt.Errorf("LookupIngressChannelOnPay err: %w", err)
182+
}
183+
receipt.PayId = payID.Bytes()
184+
frame.Message = &rpc.CelerMsg{
185+
ToAddr: frame.Message.GetToAddr(),
186+
Message: &rpc.CelerMsg_CondPayReceipt{
187+
CondPayReceipt: receipt,
188+
},
189+
}
190+
return peer, nil
191+
}
192+
return ctype.ZeroAddr, fmt.Errorf("invalid cross net pay state %d", state)
193+
}

handlers/msghdl/handle_cond_pay_request.go

Lines changed: 158 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ func (h *CelerMsgHandler) condPayRequestInbound(frame *common.MsgFrame) error {
5959
logEntry.Src = ctype.Bytes2Hex(pay.GetSrc())
6060
logEntry.Dst = ctype.Bytes2Hex(pay.GetDest())
6161

62+
if request.GetCrossNet().GetCrossing() {
63+
// proceed as crossnet payment
64+
return h.crossNetPayInbound(frame, pay, payID, logEntry)
65+
}
66+
6267
// Sign the state in advance, verify request later
6368
mySig, err := h.signer.SignEthMessage(request.GetStateOnlyPeerFromSig().GetSimplexState())
6469
if err != nil {
@@ -455,17 +460,53 @@ func (h *CelerMsgHandler) condPayRequestOutbound(frame *common.MsgFrame) error {
455460
} else if logEntry.GetPayId() != ctype.PayID2Hex(payID) {
456461
logEntry.Error = append(logEntry.Error, "different payID:"+ctype.PayID2Hex(payID))
457462
}
463+
464+
isRecipient := false
465+
var originalPayID ctype.PayIDType
458466
if dest == h.nodeConfig.GetOnChainAddr() {
467+
xnet := request.GetCrossNet()
468+
if xnet.GetDstNetId() == 0 {
469+
isRecipient = true
470+
} else {
471+
myNetId, err2 := h.dal.GetNetId()
472+
if err2 != nil {
473+
return fmt.Errorf("GetNetId err: %w", err2)
474+
}
475+
if myNetId == xnet.GetDstNetId() {
476+
isRecipient = true
477+
originalPayID = ctype.PayBytes2PayID(xnet.GetOriginalPay())
478+
err = h.dal.InsertCrossNetPay(
479+
payID, originalPayID, xnet.GetOriginalPay(), structs.CrossNetPay_DST,
480+
xnet.GetSrcNetId(), xnet.GetDstNetId(), ctype.ZeroAddr, 0)
481+
if err != nil {
482+
return fmt.Errorf("InsertCrossNetPay err: %w", err)
483+
}
484+
}
485+
}
486+
}
487+
488+
if isRecipient {
459489
// reply conPay receipt
460490
log.Debugln("Reply pay receipt", payID.Hex())
461-
sigOfCondPay, err2 := h.signer.SignEthMessage(payBytes)
491+
signedPayBytes := payBytes
492+
if request.GetCrossNet().GetDstNetId() != 0 {
493+
err = h.verifyCrossNetPay(pay, request.GetCrossNet().GetOriginalPay(), request.GetCrossNet().GetSrcNetId())
494+
if err != nil {
495+
return err
496+
}
497+
signedPayBytes = request.GetCrossNet().GetOriginalPay()
498+
}
499+
sigOfCondPay, err2 := h.signer.SignEthMessage(signedPayBytes)
462500
if err2 != nil {
463501
return err2
464502
}
465503
receipt := &rpc.CondPayReceipt{
466-
PayId: payID[:],
504+
PayId: payID.Bytes(),
467505
PayDestSig: sigOfCondPay,
468506
}
507+
if originalPayID != ctype.ZeroPayID {
508+
receipt.OriginalPayId = originalPayID.Bytes()
509+
}
469510
celerMsg := &rpc.CelerMsg{
470511
ToAddr: pay.Src,
471512
Message: &rpc.CelerMsg_CondPayReceipt{
@@ -482,7 +523,7 @@ func (h *CelerMsgHandler) condPayRequestOutbound(frame *common.MsgFrame) error {
482523
// Forward condPay to next hop if I am not the destination
483524
log.Debugln("Forward", payID.Hex())
484525
delegable, proof, description := h.checkPayDelegable(&pay, ctype.Bytes2Addr(pay.GetDest()), logEntry)
485-
peerTo, err := h.messager.ForwardCondPayRequest(payBytes, request.GetNote(), delegable, logEntry)
526+
peerTo, err := h.messager.ForwardCondPayRequest(payBytes, request.GetNote(), delegable, request.GetCrossNet(), logEntry)
486527
if err != nil {
487528
if delegable && errors.Is(err, common.ErrPeerNotOnline) {
488529
return h.delegatePay(payID, &pay, payBytes, description, proof, peerFrom, dest, logEntry)
@@ -594,3 +635,117 @@ func (h *CelerMsgHandler) checkPayDelegable(
594635

595636
return delegable, proof, description
596637
}
638+
639+
func (h *CelerMsgHandler) crossNetPayInbound(
640+
frame *common.MsgFrame, pay entity.ConditionalPay, payID ctype.PayIDType, logEntry *pem.PayEventMessage) error {
641+
request := frame.Message.GetCondPayRequest()
642+
xnet := request.GetCrossNet()
643+
originalPayId := ctype.PayBytes2PayID(xnet.GetOriginalPay())
644+
645+
logEntry.Xnet.SrcNetId = xnet.GetSrcNetId()
646+
logEntry.Xnet.DstNetId = xnet.GetDstNetId()
647+
logEntry.Xnet.OriginalPayId = ctype.PayID2Hex(originalPayId)
648+
logEntry.Xnet.FromPayId = ctype.PayID2Hex(payID)
649+
logEntry.Xnet.State = pem.CrossNetPayState_XNET_INGRESS
650+
651+
bridgeAddr := frame.PeerAddr
652+
bridgeNetId, found, err := h.dal.GetNetBridge(bridgeAddr)
653+
if err != nil {
654+
return fmt.Errorf("GetNetBridge err: %w", err)
655+
}
656+
if !found {
657+
return fmt.Errorf("bridgeNetId not found")
658+
}
659+
logEntry.Xnet.FromBridgeId = bridgeNetId
660+
661+
if ctype.Bytes2Addr(pay.GetDest()) == h.nodeConfig.GetOnChainAddr() {
662+
return fmt.Errorf("ingress bridge cannot be the dest addr")
663+
}
664+
665+
newPay := pay
666+
if pay.GetTransferFunc().GetMaxTransfer().GetToken().GetTokenType() != entity.TokenType_ETH {
667+
localToken, found, err2 := h.dal.GetLocalToken(bridgeNetId, pay.GetTransferFunc().GetMaxTransfer().GetToken())
668+
if err2 != nil {
669+
return fmt.Errorf("GetLocalToken err: %w", err2)
670+
}
671+
if !found {
672+
return fmt.Errorf("local token not found")
673+
}
674+
newPay.TransferFunc.MaxTransfer.Token = localToken
675+
}
676+
// TODO: update resolve dealine and timeout, check conditions
677+
newPay.ResolveDeadline = h.monitorService.GetCurrentBlockNumber().Uint64() + xnet.GetTimeout()
678+
newPay.ResolveTimeout = config.PayResolveTimeout
679+
newPay.PayResolver = h.nodeConfig.GetPayResolverContract().GetAddr().Bytes()
680+
newPayID := ctype.Pay2PayID(&newPay)
681+
newPayBytes, err := proto.Marshal(&newPay)
682+
if err != nil {
683+
return err
684+
}
685+
686+
err = h.dal.InsertCrossNetPay(
687+
newPayID, originalPayId, xnet.GetOriginalPay(), structs.CrossNetPay_INGRESS, xnet.GetSrcNetId(), xnet.GetDstNetId(),
688+
bridgeAddr, bridgeNetId)
689+
if err != nil {
690+
return fmt.Errorf("InsertCrossNetPay err: %w", err)
691+
}
692+
693+
xnet.Crossing = false
694+
xnet.BridgeAddr = nil
695+
xnet.BridgeNetId = 0
696+
xnet.Timeout = 0
697+
698+
frame.Message = &rpc.CelerMsg{
699+
Message: &rpc.CelerMsg_CondPayRequest{
700+
CondPayRequest: &rpc.CondPayRequest{
701+
CondPay: newPayBytes,
702+
Note: request.GetNote(),
703+
CrossNet: xnet,
704+
},
705+
},
706+
}
707+
708+
logEntry.PayId = ctype.PayID2Hex(newPayID)
709+
logEntry.Token = utils.PrintTokenInfo(newPay.GetTransferFunc().GetMaxTransfer().GetToken())
710+
711+
return nil
712+
}
713+
714+
func (h *CelerMsgHandler) verifyCrossNetPay(pay entity.ConditionalPay, originalPayBytes []byte, srcNetId uint64) error {
715+
var originalPay entity.ConditionalPay
716+
err := proto.Unmarshal(originalPayBytes, &originalPay)
717+
if err != nil {
718+
return err
719+
}
720+
if originalPay.GetTransferFunc().GetMaxTransfer().GetToken().GetTokenType() != entity.TokenType_ETH {
721+
token, found, err2 := h.dal.GetLocalToken(srcNetId, originalPay.GetTransferFunc().GetMaxTransfer().GetToken())
722+
if err2 != nil {
723+
return fmt.Errorf("GetLocalToken err: %w", err2)
724+
}
725+
if !found {
726+
return fmt.Errorf("local token not found")
727+
}
728+
originalPay.TransferFunc.MaxTransfer.Token = token
729+
}
730+
731+
pay.ResolveDeadline = 0
732+
pay.ResolveTimeout = 0
733+
pay.PayResolver = nil
734+
originalPay.ResolveDeadline = 0
735+
originalPay.ResolveTimeout = 0
736+
originalPay.PayResolver = nil
737+
738+
b1, err := proto.Marshal(&pay)
739+
if err != nil {
740+
return err
741+
}
742+
b2, err := proto.Marshal(&originalPay)
743+
if err != nil {
744+
return err
745+
}
746+
if bytes.Compare(b1, b2) != 0 {
747+
return fmt.Errorf("original pay not match")
748+
}
749+
750+
return nil
751+
}

handlers/msghdl/handle_hop_ack_state.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ func (h *CelerMsgHandler) HandleHopAckState(frame *common.MsgFrame) error {
150150
resendLogEntry.PayId = ctype.PayID2Hex(payID)
151151
resendLogEntry.Dst = ctype.Bytes2Hex(pay.GetDest())
152152
resendLogEntry.DirectPay = directPay
153-
err = h.messager.SendCondPayRequest(req.GetCondPay(), req.GetNote(), resendLogEntry)
153+
err = h.messager.SendCondPayRequest(req.GetCondPay(), req.GetNote(), req.GetCrossNet(), resendLogEntry)
154154
if err != nil {
155155
log.Error(err)
156156
resendLogEntry.Error = append(resendLogEntry.Error, err.Error())

0 commit comments

Comments
 (0)