Merge pull request #131 from meshplus/feat/asset-exchange

feat(transaction): add asset exchange contract
This commit is contained in:
Sandy Zhou 2020-07-31 11:17:27 +08:00 committed by GitHub
commit 003c289f6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 432 additions and 44 deletions

40
api/grpc/sign.go Normal file
View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -309,3 +309,7 @@ func (bxh *BitXHub) raiseUlimit(limitNew uint64) error {
return nil
}
func (bxh *BitXHub) GetPrivKey() *repo.Key {
return bxh.repo.Key
}

View File

@ -11,6 +11,7 @@ const (
RoleContractAddr BoltContractAddress = "0x000000000000000000000000000000000000000d"
AppchainMgrContractAddr BoltContractAddress = "0x000000000000000000000000000000000000000e"
TransactionMgrContractAddr BoltContractAddress = "0x000000000000000000000000000000000000000f"
AssetExchangeContractAddr BoltContractAddress = "0x0000000000000000000000000000000000000010"
)
func (addr BoltContractAddress) Address() types.Address {

View File

@ -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 {

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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)

View File

@ -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)
}
}