Merge pull request #131 from meshplus/feat/asset-exchange
feat(transaction): add asset exchange contract
This commit is contained in:
commit
003c289f6e
|
@ -0,0 +1,40 @@
|
|||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/meshplus/bitxhub-model/pb"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (cbs *ChainBrokerService) GetAssetExchangeSigns(ctx context.Context, req *pb.AssetExchangeSignsRequest) (*pb.SignResponse, error) {
|
||||
var (
|
||||
wg = sync.WaitGroup{}
|
||||
result = make(map[string][]byte)
|
||||
)
|
||||
|
||||
wg.Add(1)
|
||||
go func(result map[string][]byte) {
|
||||
for k, v := range cbs.api.Broker().FetchAssetExchangeSignsFromOtherPeers(req.Id) {
|
||||
result[k] = v
|
||||
}
|
||||
wg.Done()
|
||||
}(result)
|
||||
|
||||
address, sign, err := cbs.api.Broker().GetAssetExchangeSign(req.Id)
|
||||
wg.Wait()
|
||||
|
||||
if err != nil {
|
||||
cbs.logger.WithFields(logrus.Fields{
|
||||
"id": req.Id,
|
||||
"err": err.Error(),
|
||||
}).Warnf("Get asset exchange sign on current node")
|
||||
} else {
|
||||
result[address] = sign
|
||||
}
|
||||
|
||||
return &pb.SignResponse{
|
||||
Sign: result,
|
||||
}, nil
|
||||
}
|
2
go.mod
2
go.mod
|
@ -23,7 +23,7 @@ require (
|
|||
github.com/magiconair/properties v1.8.1
|
||||
github.com/meshplus/bitxhub-core v0.1.0-rc1.0.20200728032028-8dba332fa0ed
|
||||
github.com/meshplus/bitxhub-kit v1.0.1-0.20200729105047-4407a5e4e168
|
||||
github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200724062514-baa44473e4d8
|
||||
github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200731025300-2bb1717059e0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/multiformats/go-multiaddr v0.2.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
|
|
10
go.sum
10
go.sum
|
@ -266,8 +266,10 @@ github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOo
|
|||
github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo=
|
||||
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
|
||||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||
github.com/hyperledger/fabric v1.4.8 h1:G0PeG/WHHAApO/PXkDAcwjur5L5+FNiVbhKidzNX4Z4=
|
||||
github.com/hyperledger/fabric v2.0.1+incompatible h1:7W+yG0gLKTC7NLcWPT3vfpnaseztPpH9wXGfAW7yvBs=
|
||||
github.com/hyperledger/fabric v2.0.1+incompatible/go.mod h1:tGFAOCT696D3rG0Vofd2dyWYLySHlh0aQjf7Q1HAju0=
|
||||
github.com/hyperledger/fabric v2.1.1+incompatible h1:cYYRv3vVg4kA6DmrixLxwn1nwBEUuYda8DsMwlaMKbY=
|
||||
github.com/hyperledger/fabric-amcl v0.0.0-20200128223036-d1aa2665426a h1:HgdNn3UYz8PdcZrLEk0IsSU4LRHp7yY2rgjIKcSiJaA=
|
||||
github.com/hyperledger/fabric-amcl v0.0.0-20200128223036-d1aa2665426a/go.mod h1:X+DIyUsaTmalOpmpQfIvFZjKHQedrURQ5t4YqquX7lE=
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20200330074707-cfe579e86986 h1:g9tgYXQPZcxRryp2/rutvfSCiiJzHNoyX7JaoXeGkZ8=
|
||||
|
@ -513,6 +515,14 @@ github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200514093243-7e8ae60d1c19 h1:D0
|
|||
github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200514093243-7e8ae60d1c19/go.mod h1:QK8aACbxtZEA3Hk1BOCirW0uxMWLsMrLDpWz9FweIKM=
|
||||
github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200724062514-baa44473e4d8 h1:FlD+ETNIVTJ3gyceEdqqo6wvBkrYiTfLB6XM0tGH1Yw=
|
||||
github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200724062514-baa44473e4d8/go.mod h1:QK8aACbxtZEA3Hk1BOCirW0uxMWLsMrLDpWz9FweIKM=
|
||||
github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200727092616-7a2b838ab1ab h1:9g/sk6C/VPQSO42ySFxOcwvcCopmH+mqXsJlLaoILEw=
|
||||
github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200727092616-7a2b838ab1ab/go.mod h1:QK8aACbxtZEA3Hk1BOCirW0uxMWLsMrLDpWz9FweIKM=
|
||||
github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200729120451-6ff9eb7fe8fc h1:40lbdmb9YKeEEhGHZH7Z6BqsapGVu1H262d7K/UWGV4=
|
||||
github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200729120451-6ff9eb7fe8fc/go.mod h1:QK8aACbxtZEA3Hk1BOCirW0uxMWLsMrLDpWz9FweIKM=
|
||||
github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200730072219-49561408ef50 h1:VKUeib9kwPkfCXxJVX8/RgbkyyKSi0ixu4rhzlB+7E4=
|
||||
github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200730072219-49561408ef50/go.mod h1:QK8aACbxtZEA3Hk1BOCirW0uxMWLsMrLDpWz9FweIKM=
|
||||
github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200731025300-2bb1717059e0 h1:HICOZKS7qw4++eT0EXioutryV0O+v6aPp1jdhjlfJyU=
|
||||
github.com/meshplus/bitxhub-model v1.0.0-rc4.0.20200731025300-2bb1717059e0/go.mod h1:QK8aACbxtZEA3Hk1BOCirW0uxMWLsMrLDpWz9FweIKM=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/pkcs11 v1.0.3 h1:iMwmD7I5225wv84WxIG/bmxz9AXjWvTWIbM/TYHvWtw=
|
||||
|
|
|
@ -309,3 +309,7 @@ func (bxh *BitXHub) raiseUlimit(limitNew uint64) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bxh *BitXHub) GetPrivKey() *repo.Key {
|
||||
return bxh.repo.Key
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ const (
|
|||
RoleContractAddr BoltContractAddress = "0x000000000000000000000000000000000000000d"
|
||||
AppchainMgrContractAddr BoltContractAddress = "0x000000000000000000000000000000000000000e"
|
||||
TransactionMgrContractAddr BoltContractAddress = "0x000000000000000000000000000000000000000f"
|
||||
AssetExchangeContractAddr BoltContractAddress = "0x0000000000000000000000000000000000000010"
|
||||
)
|
||||
|
||||
func (addr BoltContractAddress) Address() types.Address {
|
||||
|
|
|
@ -38,6 +38,9 @@ type BrokerAPI interface {
|
|||
|
||||
// OrderReady
|
||||
OrderReady() bool
|
||||
|
||||
FetchAssetExchangeSignsFromOtherPeers(id string) map[string][]byte
|
||||
GetAssetExchangeSign(id string) (string, []byte, error)
|
||||
}
|
||||
|
||||
type NetworkAPI interface {
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
package coreapi
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/meshplus/bitxhub-kit/types"
|
||||
"github.com/meshplus/bitxhub-model/pb"
|
||||
"github.com/meshplus/bitxhub/internal/constant"
|
||||
"github.com/meshplus/bitxhub/internal/coreapi/api"
|
||||
"github.com/meshplus/bitxhub/internal/executor/contracts"
|
||||
"github.com/meshplus/bitxhub/internal/model"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
@ -102,3 +108,76 @@ func (b *BrokerAPI) RemovePier(key string) {
|
|||
func (b *BrokerAPI) OrderReady() bool {
|
||||
return b.bxh.Order.Ready()
|
||||
}
|
||||
|
||||
func (b *BrokerAPI) FetchAssetExchangeSignsFromOtherPeers(id string) map[string][]byte {
|
||||
var (
|
||||
result = make(map[string][]byte)
|
||||
wg = sync.WaitGroup{}
|
||||
lock = sync.Mutex{}
|
||||
)
|
||||
|
||||
wg.Add(len(b.bxh.PeerMgr.OtherPeers()))
|
||||
for pid := range b.bxh.PeerMgr.OtherPeers() {
|
||||
go func(pid uint64, result map[string][]byte, wg *sync.WaitGroup, lock *sync.Mutex) {
|
||||
address, sign, err := b.requestAssetExchangeSignFromPeer(pid, id)
|
||||
if err != nil {
|
||||
b.logger.WithFields(logrus.Fields{
|
||||
"pid": pid,
|
||||
"err": err.Error(),
|
||||
}).Warnf("Get asset exchange sign with error")
|
||||
} else {
|
||||
lock.Lock()
|
||||
result[address] = sign
|
||||
lock.Unlock()
|
||||
}
|
||||
wg.Done()
|
||||
}(pid, result, &wg, &lock)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (b *BrokerAPI) requestAssetExchangeSignFromPeer(peerId uint64, assetExchangeId string) (string, []byte, error) {
|
||||
req := pb.Message{
|
||||
Type: pb.Message_FETCH_ASSET_EXCHANEG_SIGN,
|
||||
Data: []byte(assetExchangeId),
|
||||
}
|
||||
|
||||
resp, err := b.bxh.PeerMgr.Send(peerId, &req)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if resp == nil || resp.Type != pb.Message_FETCH_ASSET_EXCHANGE_SIGN_ACK {
|
||||
return "", nil, fmt.Errorf("invalid asset exchange sign resp")
|
||||
}
|
||||
|
||||
data := model.MerkleWrapperSign{}
|
||||
if err := data.Unmarshal(resp.Data); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return data.Address, data.Signature, nil
|
||||
}
|
||||
|
||||
func (b *BrokerAPI) GetAssetExchangeSign(id string) (string, []byte, error) {
|
||||
ok, record := b.bxh.Ledger.GetState(constant.AssetExchangeContractAddr.Address(), []byte(contracts.AssetExchangeKey(id)))
|
||||
if !ok {
|
||||
return "", nil, fmt.Errorf("cannot find asset exchange record with id %s", id)
|
||||
}
|
||||
|
||||
aer := contracts.AssetExchangeRecord{}
|
||||
if err := json.Unmarshal(record, &aer); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
hash := sha256.Sum256([]byte(fmt.Sprintf("%s-%d", id, aer.Status)))
|
||||
key := b.bxh.GetPrivKey()
|
||||
sign, err := key.PrivKey.Sign(hash[:])
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("fetch asset exchange sign: %w", err)
|
||||
}
|
||||
|
||||
return key.Address, sign, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
package contracts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/meshplus/bitxhub-model/pb"
|
||||
"github.com/meshplus/bitxhub/pkg/vm/boltvm"
|
||||
)
|
||||
|
||||
type AssetExchange struct {
|
||||
boltvm.Stub
|
||||
}
|
||||
|
||||
type AssetExchangeStatus uint64
|
||||
type AssetExchangeType uint64
|
||||
|
||||
type AssetExchangeRecord struct {
|
||||
Chain0 string
|
||||
Chain1 string
|
||||
Status AssetExchangeStatus
|
||||
Info pb.AssetExchangeInfo
|
||||
}
|
||||
|
||||
const (
|
||||
ASSET_PREFIX = "asset-"
|
||||
AssetExchangeInit AssetExchangeStatus = 0
|
||||
AssetExchangeRedeem AssetExchangeStatus = 1
|
||||
AssetExchangeRefund AssetExchangeStatus = 2
|
||||
)
|
||||
|
||||
func (t *AssetExchange) Init(from, to string, info []byte) *boltvm.Response {
|
||||
aei := pb.AssetExchangeInfo{}
|
||||
if err := aei.Unmarshal(info); err != nil {
|
||||
return boltvm.Error(err.Error())
|
||||
}
|
||||
|
||||
if t.Has(AssetExchangeKey(aei.Id)) {
|
||||
return boltvm.Error(fmt.Sprintf("asset exhcange id already exists"))
|
||||
}
|
||||
|
||||
if err := checkAssetExchangeInfo(&aei); err != nil {
|
||||
return boltvm.Error(err.Error())
|
||||
}
|
||||
|
||||
aer := AssetExchangeRecord{
|
||||
Chain0: from,
|
||||
Chain1: to,
|
||||
Status: AssetExchangeInit,
|
||||
Info: aei,
|
||||
}
|
||||
t.SetObject(AssetExchangeKey(aei.Id), aer)
|
||||
|
||||
return boltvm.Success(nil)
|
||||
}
|
||||
|
||||
func (t *AssetExchange) Redeem(from, to string, info []byte) *boltvm.Response {
|
||||
if err := t.confirm(from, to, info, AssetExchangeRedeem); err != nil {
|
||||
return boltvm.Error(err.Error())
|
||||
}
|
||||
|
||||
return boltvm.Success(nil)
|
||||
}
|
||||
|
||||
func (t *AssetExchange) Refund(from, to string, info []byte) *boltvm.Response {
|
||||
if err := t.confirm(from, to, info, AssetExchangeRefund); err != nil {
|
||||
return boltvm.Error(err.Error())
|
||||
}
|
||||
|
||||
return boltvm.Success(nil)
|
||||
}
|
||||
|
||||
func (t *AssetExchange) confirm(from, to string, payload []byte, status AssetExchangeStatus) error {
|
||||
id := string(payload)
|
||||
aer := AssetExchangeRecord{}
|
||||
ok := t.GetObject(AssetExchangeKey(id), &aer)
|
||||
if !ok {
|
||||
return fmt.Errorf("asset exchange record does not exist")
|
||||
}
|
||||
|
||||
if aer.Status != AssetExchangeInit {
|
||||
return fmt.Errorf("asset exchange status for this id is not 'Init'")
|
||||
}
|
||||
|
||||
if !(aer.Chain0 == from && aer.Chain1 == to) && !(aer.Chain0 == to && aer.Chain1 == from) {
|
||||
return fmt.Errorf("invalid participator of asset exchange id %s", id)
|
||||
}
|
||||
|
||||
// TODO: verify proof
|
||||
|
||||
aer.Status = status
|
||||
t.SetObject(AssetExchangeKey(id), aer)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *AssetExchange) GetStatus(id string) *boltvm.Response {
|
||||
aer := AssetExchangeRecord{}
|
||||
ok := t.GetObject(AssetExchangeKey(id), &aer)
|
||||
if !ok {
|
||||
return boltvm.Error(fmt.Sprintf("asset exchange record does not exist"))
|
||||
}
|
||||
|
||||
return boltvm.Success([]byte(strconv.Itoa(int(aer.Status))))
|
||||
}
|
||||
|
||||
func AssetExchangeKey(id string) string {
|
||||
return fmt.Sprintf("%s-%s", ASSET_PREFIX, id)
|
||||
}
|
||||
|
||||
func checkAssetExchangeInfo(aei *pb.AssetExchangeInfo) error {
|
||||
if aei.SenderOnDst == "" ||
|
||||
aei.ReceiverOnSrc == "" ||
|
||||
aei.SenderOnSrc == "" ||
|
||||
aei.ReceiverOnDst == "" ||
|
||||
aei.AssetOnSrc == 0 ||
|
||||
aei.AssetOnDst == 0 {
|
||||
return fmt.Errorf("illegal asset exchange info")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkAssetExchangeInfoPair(aei0, aei1 *pb.AssetExchangeInfo) error {
|
||||
if aei0.SenderOnSrc != aei1.ReceiverOnDst ||
|
||||
aei0.ReceiverOnSrc != aei1.SenderOnDst ||
|
||||
aei0.SenderOnDst != aei1.ReceiverOnSrc ||
|
||||
aei0.ReceiverOnDst != aei1.SenderOnSrc ||
|
||||
aei0.AssetOnSrc != aei1.AssetOnDst ||
|
||||
aei0.AssetOnDst != aei1.AssetOnSrc {
|
||||
return fmt.Errorf("unmatched exchange info pair")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -8,7 +8,6 @@ import (
|
|||
appchainMgr "github.com/meshplus/bitxhub-core/appchain-mgr"
|
||||
"github.com/meshplus/bitxhub-kit/types"
|
||||
"github.com/meshplus/bitxhub-model/pb"
|
||||
|
||||
"github.com/meshplus/bitxhub/internal/constant"
|
||||
"github.com/meshplus/bitxhub/pkg/vm/boltvm"
|
||||
)
|
||||
|
@ -99,8 +98,12 @@ func (x *InterchainManager) HandleIBTP(data []byte) *boltvm.Response {
|
|||
|
||||
if pb.IBTP_INTERCHAIN == ibtp.Type {
|
||||
res = x.beginTransaction(ibtp)
|
||||
} else {
|
||||
} else if pb.IBTP_RECEIPT_SUCCESS == ibtp.Type || pb.IBTP_RECEIPT_FAILURE == ibtp.Type {
|
||||
res = x.reportTransaction(ibtp)
|
||||
} else if pb.IBTP_ASSET_EXCHANGE_INIT == ibtp.Type ||
|
||||
pb.IBTP_ASSET_EXCHANGE_REDEEM == ibtp.Type ||
|
||||
pb.IBTP_ASSET_EXCHANGE_REFUND == ibtp.Type {
|
||||
res = x.handleAssetExchange(ibtp)
|
||||
}
|
||||
|
||||
if !res.Ok {
|
||||
|
@ -173,7 +176,10 @@ func (x *InterchainManager) checkIBTP(ibtp *pb.IBTP, interchain *Interchain) err
|
|||
return fmt.Errorf("invalid interchain transaction")
|
||||
}
|
||||
|
||||
if pb.IBTP_INTERCHAIN == ibtp.Type {
|
||||
if pb.IBTP_INTERCHAIN == ibtp.Type ||
|
||||
pb.IBTP_ASSET_EXCHANGE_INIT == ibtp.Type ||
|
||||
pb.IBTP_ASSET_EXCHANGE_REDEEM == ibtp.Type ||
|
||||
pb.IBTP_ASSET_EXCHANGE_REFUND == ibtp.Type {
|
||||
if ibtp.From != x.Caller() {
|
||||
return fmt.Errorf("ibtp from != caller")
|
||||
}
|
||||
|
@ -184,7 +190,7 @@ func (x *InterchainManager) checkIBTP(ibtp *pb.IBTP, interchain *Interchain) err
|
|||
}
|
||||
} else {
|
||||
if ibtp.To != x.Caller() {
|
||||
return fmt.Errorf("ibtp from != caller")
|
||||
return fmt.Errorf("ibtp to != caller")
|
||||
}
|
||||
|
||||
idx := interchain.ReceiptCounter[ibtp.To]
|
||||
|
@ -201,7 +207,10 @@ func (x *InterchainManager) checkIBTP(ibtp *pb.IBTP, interchain *Interchain) err
|
|||
func (x *InterchainManager) ProcessIBTP(ibtp *pb.IBTP, interchain *Interchain) {
|
||||
m := make(map[string]uint64)
|
||||
|
||||
if pb.IBTP_INTERCHAIN == ibtp.Type {
|
||||
if pb.IBTP_INTERCHAIN == ibtp.Type ||
|
||||
pb.IBTP_ASSET_EXCHANGE_INIT == ibtp.Type ||
|
||||
pb.IBTP_ASSET_EXCHANGE_REDEEM == ibtp.Type ||
|
||||
pb.IBTP_ASSET_EXCHANGE_REFUND == ibtp.Type {
|
||||
interchain.InterchainCounter[ibtp.To]++
|
||||
x.SetObject(x.appchainKey(ibtp.From), interchain)
|
||||
x.SetObject(x.indexMapKey(ibtp.ID()), x.GetTxHash())
|
||||
|
@ -234,7 +243,7 @@ func (x *InterchainManager) beginMultiTargetsTransaction(ibtps *pb.IBTPs) *boltv
|
|||
args = append(args, pb.String(childTxId))
|
||||
}
|
||||
|
||||
return x.CrossInvoke(constant.TransactionMgrContractAddr.String(), "Begin", args...)
|
||||
return x.CrossInvoke(constant.TransactionMgrContractAddr.String(), "BeginMultiTXs", args...)
|
||||
}
|
||||
|
||||
func (x *InterchainManager) beginTransaction(ibtp *pb.IBTP) *boltvm.Response {
|
||||
|
@ -243,7 +252,7 @@ func (x *InterchainManager) beginTransaction(ibtp *pb.IBTP) *boltvm.Response {
|
|||
}
|
||||
|
||||
func (x *InterchainManager) reportTransaction(ibtp *pb.IBTP) *boltvm.Response {
|
||||
txId := fmt.Sprintf("%s-%s-%d", ibtp.To, ibtp.From, ibtp.Index)
|
||||
txId := fmt.Sprintf("%s-%s-%d", ibtp.From, ibtp.To, ibtp.Index)
|
||||
result := int32(0)
|
||||
if ibtp.Type == pb.IBTP_RECEIPT_FAILURE {
|
||||
result = 1
|
||||
|
@ -251,6 +260,24 @@ func (x *InterchainManager) reportTransaction(ibtp *pb.IBTP) *boltvm.Response {
|
|||
return x.CrossInvoke(constant.TransactionMgrContractAddr.String(), "Report", pb.String(txId), pb.Int32(result))
|
||||
}
|
||||
|
||||
func (x *InterchainManager) handleAssetExchange(ibtp *pb.IBTP) *boltvm.Response {
|
||||
var method string
|
||||
|
||||
switch ibtp.Type {
|
||||
case pb.IBTP_ASSET_EXCHANGE_INIT:
|
||||
method = "Init"
|
||||
case pb.IBTP_ASSET_EXCHANGE_REDEEM:
|
||||
method = "Redeem"
|
||||
case pb.IBTP_ASSET_EXCHANGE_REFUND:
|
||||
method = "Refund"
|
||||
default:
|
||||
return boltvm.Error("unsupported asset exchange type")
|
||||
}
|
||||
|
||||
return x.CrossInvoke(constant.AssetExchangeContractAddr.String(), method, pb.String(ibtp.From),
|
||||
pb.String(ibtp.To), pb.Bytes(ibtp.Extra))
|
||||
}
|
||||
|
||||
func (x *InterchainManager) GetIBTPByID(id string) *boltvm.Response {
|
||||
arr := strings.Split(id, "-")
|
||||
if len(arr) != 3 {
|
||||
|
|
|
@ -2,26 +2,21 @@ package contracts
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/meshplus/bitxhub-model/pb"
|
||||
"github.com/meshplus/bitxhub/pkg/vm/boltvm"
|
||||
)
|
||||
|
||||
type TransactionStatus string
|
||||
|
||||
const (
|
||||
PREFIX = "tx-"
|
||||
StatusBegin TransactionStatus = "BEGIN"
|
||||
StatusSuccess TransactionStatus = "SUCCESS"
|
||||
StatusFail TransactionStatus = "FAIL"
|
||||
)
|
||||
const PREFIX = "tx-"
|
||||
|
||||
type TransactionManager struct {
|
||||
boltvm.Stub
|
||||
}
|
||||
|
||||
type TransactionInfo struct {
|
||||
globalState TransactionStatus
|
||||
childTxInfo map[string]TransactionStatus
|
||||
GlobalState pb.TransactionStatus
|
||||
ChildTxInfo map[string]pb.TransactionStatus
|
||||
}
|
||||
|
||||
func (t *TransactionManager) BeginMultiTXs(globalId string, childTxIds ...string) *boltvm.Response {
|
||||
|
@ -29,17 +24,17 @@ func (t *TransactionManager) BeginMultiTXs(globalId string, childTxIds ...string
|
|||
return boltvm.Error("Transaction id already exists")
|
||||
}
|
||||
|
||||
txInfo := &TransactionInfo{
|
||||
globalState: StatusBegin,
|
||||
childTxInfo: make(map[string]TransactionStatus),
|
||||
txInfo := TransactionInfo{
|
||||
GlobalState: pb.TransactionStatus_BEGIN,
|
||||
ChildTxInfo: make(map[string]pb.TransactionStatus),
|
||||
}
|
||||
|
||||
for _, childTxId := range childTxIds {
|
||||
txInfo.childTxInfo[childTxId] = StatusBegin
|
||||
txInfo.ChildTxInfo[childTxId] = pb.TransactionStatus_BEGIN
|
||||
t.Set(childTxId, []byte(globalId))
|
||||
}
|
||||
|
||||
t.SetObject(t.txInfoKey(globalId), txInfo)
|
||||
t.SetObject(t.globalTxInfoKey(globalId), txInfo)
|
||||
|
||||
return boltvm.Success(nil)
|
||||
}
|
||||
|
@ -49,73 +44,104 @@ func (t *TransactionManager) Begin(txId string) *boltvm.Response {
|
|||
return boltvm.Error("Transaction id already exists")
|
||||
}
|
||||
|
||||
t.Set(t.txInfoKey(txId), []byte(StatusBegin))
|
||||
t.SetObject(t.txInfoKey(txId), pb.TransactionStatus_BEGIN)
|
||||
|
||||
return boltvm.Success(nil)
|
||||
}
|
||||
|
||||
func (t *TransactionManager) Report(txId string, result int32) *boltvm.Response {
|
||||
ok, val := t.Get(t.txInfoKey(txId))
|
||||
var status pb.TransactionStatus
|
||||
ok := t.GetObject(t.txInfoKey(txId), &status)
|
||||
if ok {
|
||||
status := TransactionStatus(val)
|
||||
if status != StatusBegin {
|
||||
if status != pb.TransactionStatus_BEGIN {
|
||||
return boltvm.Error(fmt.Sprintf("transaction with Id %s is finished", txId))
|
||||
}
|
||||
|
||||
if result == 0 {
|
||||
t.Set(t.txInfoKey(txId), []byte(StatusSuccess))
|
||||
t.SetObject(t.txInfoKey(txId), pb.TransactionStatus_SUCCESS)
|
||||
} else {
|
||||
t.Set(t.txInfoKey(txId), []byte(StatusFail))
|
||||
t.SetObject(t.txInfoKey(txId), pb.TransactionStatus_FAILURE)
|
||||
}
|
||||
} else {
|
||||
ok, val = t.Get(txId)
|
||||
ok, val := t.Get(txId)
|
||||
if !ok {
|
||||
return boltvm.Error(fmt.Sprintf("cannot get global id of child tx id %s", txId))
|
||||
}
|
||||
|
||||
globalId := string(val)
|
||||
txInfo := &TransactionInfo{}
|
||||
if !t.GetObject(t.txInfoKey(globalId), &txInfo) {
|
||||
txInfo := TransactionInfo{}
|
||||
if !t.GetObject(t.globalTxInfoKey(globalId), &txInfo) {
|
||||
return boltvm.Error(fmt.Sprintf("transaction global id %s does not exist", globalId))
|
||||
}
|
||||
|
||||
if txInfo.globalState != StatusBegin {
|
||||
if txInfo.GlobalState != pb.TransactionStatus_BEGIN {
|
||||
return boltvm.Error(fmt.Sprintf("transaction with global Id %s is finished", globalId))
|
||||
}
|
||||
|
||||
status, ok := txInfo.childTxInfo[txId]
|
||||
status, ok := txInfo.ChildTxInfo[txId]
|
||||
if !ok {
|
||||
return boltvm.Error(fmt.Sprintf("%s is not in transaction %s", txId, globalId))
|
||||
return boltvm.Error(fmt.Sprintf("%s is not in transaction %s, %v", txId, globalId, txInfo))
|
||||
}
|
||||
|
||||
if status != StatusBegin {
|
||||
if status != pb.TransactionStatus_BEGIN {
|
||||
return boltvm.Error(fmt.Sprintf("%s has already reported result", txId))
|
||||
}
|
||||
|
||||
if result == 0 {
|
||||
txInfo.childTxInfo[txId] = StatusSuccess
|
||||
txInfo.ChildTxInfo[txId] = pb.TransactionStatus_SUCCESS
|
||||
count := 0
|
||||
for _, res := range txInfo.childTxInfo {
|
||||
if res != StatusSuccess {
|
||||
for _, res := range txInfo.ChildTxInfo {
|
||||
if res != pb.TransactionStatus_SUCCESS {
|
||||
break
|
||||
}
|
||||
count++
|
||||
}
|
||||
|
||||
if count == len(txInfo.childTxInfo) {
|
||||
txInfo.globalState = StatusSuccess
|
||||
if count == len(txInfo.ChildTxInfo) {
|
||||
txInfo.GlobalState = pb.TransactionStatus_SUCCESS
|
||||
}
|
||||
} else {
|
||||
txInfo.childTxInfo[txId] = StatusFail
|
||||
txInfo.globalState = StatusFail
|
||||
txInfo.ChildTxInfo[txId] = pb.TransactionStatus_FAILURE
|
||||
txInfo.GlobalState = pb.TransactionStatus_FAILURE
|
||||
}
|
||||
|
||||
t.SetObject(t.txInfoKey(globalId), txInfo)
|
||||
t.SetObject(t.globalTxInfoKey(globalId), txInfo)
|
||||
}
|
||||
|
||||
return boltvm.Success(nil)
|
||||
}
|
||||
|
||||
func (t *TransactionManager) GetStatus(txId string) *boltvm.Response {
|
||||
var status pb.TransactionStatus
|
||||
ok := t.GetObject(t.txInfoKey(txId), &status)
|
||||
if ok {
|
||||
return boltvm.Success([]byte(strconv.Itoa(int(status))))
|
||||
}
|
||||
|
||||
txInfo := TransactionInfo{}
|
||||
ok = t.GetObject(t.globalTxInfoKey(txId), &txInfo)
|
||||
if ok {
|
||||
return boltvm.Success([]byte(strconv.Itoa(int(txInfo.GlobalState))))
|
||||
}
|
||||
|
||||
ok, val := t.Get(txId)
|
||||
if !ok {
|
||||
return boltvm.Error(fmt.Sprintf("cannot get global id of child tx id %s", txId))
|
||||
}
|
||||
|
||||
globalId := string(val)
|
||||
txInfo = TransactionInfo{}
|
||||
if !t.GetObject(t.globalTxInfoKey(globalId), &txInfo) {
|
||||
return boltvm.Error(fmt.Sprintf("transaction info for global id %s does not exist", globalId))
|
||||
}
|
||||
|
||||
return boltvm.Success([]byte(strconv.Itoa(int(txInfo.GlobalState))))
|
||||
}
|
||||
|
||||
func (t *TransactionManager) txInfoKey(id string) string {
|
||||
return fmt.Sprintf("%s-%s", PREFIX, id)
|
||||
}
|
||||
|
||||
func (t *TransactionManager) globalTxInfoKey(id string) string {
|
||||
return fmt.Sprintf("global-%s-%s", PREFIX, id)
|
||||
}
|
||||
|
|
|
@ -203,6 +203,12 @@ func registerBoltContracts() map[string]boltvm.Contract {
|
|||
Address: constant.TransactionMgrContractAddr.String(),
|
||||
Contract: &contracts.TransactionManager{},
|
||||
},
|
||||
{
|
||||
Enabled: true,
|
||||
Name: "asset exchange service",
|
||||
Address: constant.AssetExchangeContractAddr.String(),
|
||||
Contract: &contracts.AssetExchange{},
|
||||
},
|
||||
}
|
||||
|
||||
return boltvm.Register(boltContracts)
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
package peermgr
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
network2 "github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/meshplus/bitxhub-model/pb"
|
||||
"github.com/meshplus/bitxhub/internal/constant"
|
||||
"github.com/meshplus/bitxhub/internal/executor/contracts"
|
||||
"github.com/meshplus/bitxhub/internal/model"
|
||||
"github.com/meshplus/bitxhub/internal/model/events"
|
||||
"github.com/meshplus/bitxhub/pkg/cert"
|
||||
|
@ -31,6 +35,8 @@ func (swarm *Swarm) handleMessage(s network.Stream, data []byte) {
|
|||
go swarm.orderMessageFeed.Send(events.OrderMessageEvent{Data: m.Data})
|
||||
case pb.Message_FETCH_BLOCK_SIGN:
|
||||
swarm.handleFetchBlockSignMessage(s, m.Data)
|
||||
case pb.Message_FETCH_ASSET_EXCHANEG_SIGN:
|
||||
swarm.handleFetchAssetExchangeSignMessage(s, m.Data)
|
||||
default:
|
||||
swarm.logger.WithField("module", "p2p").Errorf("can't handle msg[type: %v]", m.Type)
|
||||
return nil
|
||||
|
@ -154,3 +160,54 @@ func (swarm *Swarm) handleFetchBlockSignMessage(s network2.Stream, data []byte)
|
|||
swarm.logger.Errorf("send block sign back: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (swarm *Swarm) handleFetchAssetExchangeSignMessage(s network2.Stream, data []byte) {
|
||||
handle := func(id string) (string, []byte, error) {
|
||||
swarm.logger.WithField("asset exchange id", id).Debug("Handle fetching asset exchange sign message")
|
||||
|
||||
ok, record := swarm.ledger.GetState(constant.AssetExchangeContractAddr.Address(), []byte(contracts.AssetExchangeKey(id)))
|
||||
if !ok {
|
||||
return "", nil, fmt.Errorf("cannot find asset exchange record with id %s", id)
|
||||
}
|
||||
|
||||
aer := contracts.AssetExchangeRecord{}
|
||||
if err := json.Unmarshal(record, &aer); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
hash := sha256.Sum256([]byte(fmt.Sprintf("%s-%d", id, aer.Status)))
|
||||
key := swarm.repo.Key
|
||||
sign, err := key.PrivKey.Sign(hash[:])
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("fetch asset exchange sign: %w", err)
|
||||
}
|
||||
|
||||
return key.Address, sign, nil
|
||||
}
|
||||
|
||||
address, signed, err := handle(string(data))
|
||||
if err != nil {
|
||||
swarm.logger.Errorf("handle fetch-asset-exchange-sign: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
m := model.MerkleWrapperSign{
|
||||
Address: address,
|
||||
Signature: signed,
|
||||
}
|
||||
|
||||
body, err := m.Marshal()
|
||||
if err != nil {
|
||||
swarm.logger.Errorf("marshal merkle wrapper sign: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
msg := &pb.Message{
|
||||
Type: pb.Message_FETCH_ASSET_EXCHANGE_SIGN_ACK,
|
||||
Data: body,
|
||||
}
|
||||
|
||||
if err := swarm.SendWithStream(s, msg); err != nil {
|
||||
swarm.logger.Errorf("send asset exchange sign back: %s", err)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue